diff --git a/pom.xml b/pom.xml index e2814d6..dd346e6 100644 --- a/pom.xml +++ b/pom.xml @@ -108,13 +108,38 @@ commons-io 2.5 + + + com.itextpdf + itext7-core + 7.0.2 + pom + + + + javax.interceptor + javax.interceptor-api + 1.2 + + + + + itext + iText Repository - releases + https://repo.itextsupport.com/releases + + + org.springframework.boot spring-boot-maven-plugin + + true + diff --git a/src/main/java/com/chlorocode/tendertracker/AWSConfiguration.java b/src/main/java/com/chlorocode/tendertracker/AWSConfiguration.java index 4d32137..d72d8ab 100644 --- a/src/main/java/com/chlorocode/tendertracker/AWSConfiguration.java +++ b/src/main/java/com/chlorocode/tendertracker/AWSConfiguration.java @@ -9,6 +9,9 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +/** + * This class is used for AWS configuration. + */ @Configuration public class AWSConfiguration { @Value("${cloud.aws.credentials.accessKey}") @@ -20,11 +23,24 @@ public class AWSConfiguration { @Value("${cloud.aws.region}") private String region; + /** + * This method is used for basic AWS credentials. + * + * @return BasicAWSCredentials + * @see BasicAWSCredentials + */ @Bean public BasicAWSCredentials basicAWSCredentials() { return new BasicAWSCredentials(accessKey, secretKey); } + /** + * This method is used for amazon S3 client. + * + * @param awsCredentials AWSCredentials + * @return AmazonS3Client + * @see AmazonS3Client + */ @Bean public AmazonS3Client amazonS3Client(AWSCredentials awsCredentials) { AmazonS3Client amazonS3Client = new AmazonS3Client(awsCredentials); diff --git a/src/main/java/com/chlorocode/tendertracker/LongProcessConfiguration.java b/src/main/java/com/chlorocode/tendertracker/LongProcessConfiguration.java new file mode 100644 index 0000000..cb6f082 --- /dev/null +++ b/src/main/java/com/chlorocode/tendertracker/LongProcessConfiguration.java @@ -0,0 +1,57 @@ +package com.chlorocode.tendertracker; + +import com.chlorocode.tendertracker.api.LongProcess; +import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler; +import org.springframework.aop.interceptor.SimpleAsyncUncaughtExceptionHandler; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.AsyncConfigurer; +import org.springframework.scheduling.annotation.EnableAsync; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; + +import java.util.concurrent.Executor; + +/** + * Created by Kyaw Min Thu on 5/1/2017. + * This class is used to control the long background process of the application. + */ +@Configuration +@EnableAsync +public class LongProcessConfiguration implements AsyncConfigurer { + + /** + * This method is used to generate the LongProcess bean. + * + * @return LongProcess + * @see LongProcess + */ + @Bean + public LongProcess longProcessBean() { + return new LongProcess(); + } + + /** + * This method is used to get the executor of async tasks. + * + * @return Executor + */ + @Override + public Executor getAsyncExecutor() { + ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor(); + taskExecutor.setMaxPoolSize(10); + taskExecutor.setThreadNamePrefix("LULExecutor-"); + taskExecutor.initialize(); + return taskExecutor; + } + + /** + * This method is used to create the AsyncUncaughtExceptionHandler. + * + * @return AsyncUncaughtExceptionHandler + */ + @Override + public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { + return new SimpleAsyncUncaughtExceptionHandler(); + } + +} \ No newline at end of file diff --git a/src/main/java/com/chlorocode/tendertracker/TendertrackerApplication.java b/src/main/java/com/chlorocode/tendertracker/TendertrackerApplication.java index c272aac..4a292ac 100644 --- a/src/main/java/com/chlorocode/tendertracker/TendertrackerApplication.java +++ b/src/main/java/com/chlorocode/tendertracker/TendertrackerApplication.java @@ -9,15 +9,20 @@ import org.springframework.data.jpa.datatables.repository.DataTablesRepositoryFactoryBean; import org.springframework.data.jpa.repository.config.EnableJpaRepositories; import org.springframework.scheduling.annotation.EnableAsync; +import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import javax.annotation.PostConstruct; import java.util.TimeZone; import java.util.concurrent.Executor; +/** + * The base class of the application. Application will be started from this class. + */ @SpringBootApplication @EnableAsync @EnableJpaRepositories(repositoryFactoryBeanClass = DataTablesRepositoryFactoryBean.class) +@EnableScheduling public class TendertrackerApplication { @Value("${application.timezone}") @@ -32,6 +37,11 @@ public static void main(String[] args) { SpringApplication.run(TendertrackerApplication.class, args); } + /** + * This method used to create the admin filter. + * + * @return FilterRegistrationBean + */ @Bean public FilterRegistrationBean adminFilter() { FilterRegistrationBean registration = new FilterRegistrationBean(); @@ -40,6 +50,11 @@ public FilterRegistrationBean adminFilter() { return registration; } + /** + * This method used to create the executor for async threads. + * + * @return Executor + */ @Bean public Executor asyncExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); diff --git a/src/main/java/com/chlorocode/tendertracker/WebSecurityConfig.java b/src/main/java/com/chlorocode/tendertracker/WebSecurityConfig.java index c789585..ed6cd58 100644 --- a/src/main/java/com/chlorocode/tendertracker/WebSecurityConfig.java +++ b/src/main/java/com/chlorocode/tendertracker/WebSecurityConfig.java @@ -12,16 +12,14 @@ import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.authentication.AuthenticationFailureHandler; -import org.springframework.security.web.authentication.AuthenticationSuccessHandler; +/** + * This class is used to control the security of the application by using spring security. + */ @Configuration @EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { - -// @Autowired -// private AuthenticationSuccessHandler myAuthenticationSuccessHandler; - @Autowired private AuthenticationFailureHandler authenticationFailureHandler; @@ -32,11 +30,22 @@ public PasswordEncoder passwordEncoder() { private AuthService authService; + /** + * Constructor. + * + * @param authService AuthService + */ @Autowired public WebSecurityConfig(AuthService authService) { this.authService = authService; } + /** + * This method is used to configure the HttpSecurity control of the application. + * + * @param http HttpSecurity + * @throws Exception Exception + */ @Override protected void configure(HttpSecurity http) throws Exception { http @@ -44,8 +53,8 @@ protected void configure(HttpSecurity http) throws Exception { .antMatchers("/registerCompany").authenticated() .antMatchers("/tenderNotification").authenticated() .antMatchers("/user/profile").authenticated() - .antMatchers("/admin").access("hasAnyRole('ADMIN','SYS_ADMIN','PREPARER')") - .antMatchers("/admin/**").access("hasAnyRole('ADMIN','PREPARER')") + .antMatchers("/admin").access("hasAnyRole('ADMIN','SYS_ADMIN','PREPARER','SUBMITTER')") + .antMatchers("/admin/**").access("hasAnyRole('ADMIN','PREPARER','SUBMITTER')") .antMatchers("/sysadm/**").access("hasRole('SYS_ADMIN')") .antMatchers("/**").permitAll() .and() @@ -55,7 +64,6 @@ protected void configure(HttpSecurity http) throws Exception { .failureUrl("/login?error") .usernameParameter("email") .defaultSuccessUrl("/") -// .successHandler(myAuthenticationSuccessHandler) .failureHandler(authenticationFailureHandler) .permitAll() .and() @@ -64,9 +72,15 @@ protected void configure(HttpSecurity http) throws Exception { .logoutSuccessUrl("/") .permitAll() .and() - .csrf(); + .csrf().ignoringAntMatchers("/restapi/**"); } + /** + * This method is used to configure the WebSecurity control of the application. + * + * @param web WebSecurity + * @throws Exception exception + */ @Override public void configure(WebSecurity web) throws Exception { web @@ -74,6 +88,12 @@ public void configure(WebSecurity web) throws Exception { .antMatchers("/resources/**", "/static/**", "/css/**", "/js/**", "/images/**", "/data/**"); } + /** + * This method is used to configure the AuthenticationManagerBuilder for login of the application. + * + * @param auth AuthenticationManagerBuilder + * @throws Exception exception + */ @Override public void configure(AuthenticationManagerBuilder auth) throws Exception { auth diff --git a/src/main/java/com/chlorocode/tendertracker/api/LongProcess.java b/src/main/java/com/chlorocode/tendertracker/api/LongProcess.java new file mode 100644 index 0000000..b0232af --- /dev/null +++ b/src/main/java/com/chlorocode/tendertracker/api/LongProcess.java @@ -0,0 +1,32 @@ +package com.chlorocode.tendertracker.api; + +import com.chlorocode.tendertracker.dao.entity.ExternalTender; +import com.chlorocode.tendertracker.service.ExternalTenderService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Async; +import org.springframework.scheduling.annotation.AsyncResult; + +import java.util.List; +import java.util.concurrent.Future; + +/** + * This class is used to handle long process threading during external tender saving process. + */ +public class LongProcess { + + @Autowired + private ExternalTenderService tenderWCService; + + /** + * This method is used to save external tender asynchronously. + * + * @param tenders list of external tender to be saved + * @return String + */ + @Async + public Future createExternalTenderList(List tenders) { + tenderWCService.createTenderWCList(tenders); + return new AsyncResult<>("success"); + } + +} diff --git a/src/main/java/com/chlorocode/tendertracker/api/WebCrawlerController.java b/src/main/java/com/chlorocode/tendertracker/api/WebCrawlerController.java new file mode 100644 index 0000000..7164a14 --- /dev/null +++ b/src/main/java/com/chlorocode/tendertracker/api/WebCrawlerController.java @@ -0,0 +1,117 @@ +package com.chlorocode.tendertracker.api; + +import com.chlorocode.tendertracker.dao.entity.ExternalTender; +import com.chlorocode.tendertracker.logging.TTLogger; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletRequest; +import java.io.Serializable; +import java.nio.charset.Charset; +import java.util.Base64; +import java.util.List; +import java.util.concurrent.atomic.AtomicLong; + +/** + * Public REST API controller to be consumed by tender crawler. + * This REST API is secured by basic HTTP authentication + */ +@RestController +@RequestMapping("/restapi") +public class WebCrawlerController { + + @Autowired + private LongProcess longProcess; + + @Value("${crawler.username}") + private String crawlerUsername; + + @Value("${crawler.password}") + private String crawlerPassword; + + private static final String template = "Hello, %s!"; + private final AtomicLong counter = new AtomicLong(); + + /** + * This method is used to display test message for testing purpose. + * + * @param name text to be displayed + * @return String + */ + @RequestMapping(path = "/greeting", method = RequestMethod.GET) + public Greeting greeting(@RequestParam(value="name", defaultValue="World") String name) { + return new Greeting(String.valueOf(counter.incrementAndGet()), + String.format(template, name)); + } + + /** + * This method is used to save external tender. + * + * @param tenders list of external tenders to be saved + * @param request HttpServletRequest + * @return ResponseEntity + */ + @RequestMapping(path = "/tenders", method = RequestMethod.POST) + public ResponseEntity tenders(@RequestBody List tenders, HttpServletRequest request) { + TTLogger.debug(this.getClass().getName(),"*******************WebCrawlerController" + this.toString() + "*********************"); + + // Validate authentication + final String authorization = request.getHeader("Authorization"); + if (authorization != null && authorization.startsWith("Basic")) { + String base64Credentials = authorization.substring("Basic".length()).trim(); + String credentials = new String(Base64.getDecoder().decode(base64Credentials), + Charset.forName("UTF-8")); + // credentials = username:password + final String[] values = credentials.split(":", 2); + + if (values.length != 2 || !values[0].equals(crawlerUsername) || !values[1].equals(crawlerPassword)) { + return new ResponseEntity(HttpStatus.UNAUTHORIZED); + } + } else { + return new ResponseEntity(HttpStatus.UNAUTHORIZED); + } + + // Proccess the request + try { + longProcess.createExternalTenderList(tenders); + } catch (Exception ex) { + TTLogger.error(this.getClass().getName(), "Error when saving External Tender", ex); + ResponseEntity responseEntity = new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); + return responseEntity; + } + + ResponseEntity responseEntity = new ResponseEntity(HttpStatus.OK); + return responseEntity; + } + + public class Greeting implements Serializable { + + private final String id; + private final String content; + + public Greeting(String id, String content) { + this.id = id; + this.content = content; + } + + public String getId() { + return id; + } + + public String getContent() { + return content; + } + + @Override + public String toString() { + return "Greeting{" + + "id=" + id + + ", content='" + content + '\'' + + '}'; + } + } + +} \ No newline at end of file diff --git a/src/main/java/com/chlorocode/tendertracker/constants/TTConstants.java b/src/main/java/com/chlorocode/tendertracker/constants/TTConstants.java index 185ef55..2c5c72c 100644 --- a/src/main/java/com/chlorocode/tendertracker/constants/TTConstants.java +++ b/src/main/java/com/chlorocode/tendertracker/constants/TTConstants.java @@ -1,11 +1,10 @@ package com.chlorocode.tendertracker.constants; -import org.springframework.data.domain.Sort; - /** - * Created by Kyaw Min Thu on 3/7/2017. + * This class is to capture all system constants. */ public class TTConstants { + public static final int OTP_VALID_HOURS = 1; public static final int OTP_LENGTH = 6; public static String OTP_CHARS = "ABCDEFGHJKLMNPQRSTUVWXYZ"; @@ -14,6 +13,9 @@ public class TTConstants { public static final String APPROVED = "approved"; public static final String REJECTED = "rejected"; + public static final int APPEAL_ACCEPT = 1; + public static final int APPEAL_REJECT = 2; + public static final int ACCOUNT_STATIC_ACTIVE = 1; public static final int ACCOUNT_STATIC_EXPIRE = 2; public static final int ACCOUNT_STATIC_LOCK = 3; @@ -36,23 +38,44 @@ public class TTConstants { public static final String PARAM_COMPANY_NAME = "company_name"; public static final String PARAM_TENDER = "tender"; public static final String PARAM_APPROVAL_ACTION = "approval_action"; + public static final String PARAM_APPEAL_ACTION = "appeal_action"; + public static final String PARAM_MILESTONE_DESCRIPTION = "milestone_description"; + public static final String PARAM_MILESTONE_DUE_DATE = "milestone_due_date"; + public static final String PARAM_MILESTONE_STATUS = "milestone_status"; + public static final String PARAM_APPEAL_COMPANY = "appeal_company"; public static final String OPEN_DATE = "openDate"; public static final String CLOSED_DATE = "closedDate"; public static final String TITLE = "title"; + public static final String CREATE_DATE = "createdDate"; + public static final String PRICE = "price"; public static final String ASC = "asc"; public static final String DESC = "desc"; + public static final String PUBLISHED_DATE = "publishedDate"; + public static final String CLOSING_DATE = "closingDate"; + public static final String DEFAULT_SORT = OPEN_DATE; public static final String DEFAULT_SORT_DIRECTION = ASC; public static final String LBL_OPEN_DATE = "Open Date"; public static final String LBL_CLOSED_DATE = "Closed Date"; public static final String LBL_TITLE = "Title"; + public static final String LBL_CREATE_DATE = "Create Date"; + public static final String LBL_PRICE = "Price"; public static final String LBL_ASC = "Ascending"; public static final String LBL_DESC = "Descending"; public static int UPDATE_TENDER = 1; public static int ADD_CORRIGENDUM = 2; + + // External tender status. + public static final String ET_STATUS_OPEN = "OPEN"; + public static final String ET_STATUS_CLOSED = "CLOSED"; + public static final String ET_STATUS_AWARDED = "AWARDED"; + public static final String ET_STATUS_NO_AWARD = "NO_AWARD"; + public static final String ET_STATUS_OTHERS = "OTHERS"; + + public static final int MILESTONE_APPROACH_DAY=3; } diff --git a/src/main/java/com/chlorocode/tendertracker/dao/BidDAO.java b/src/main/java/com/chlorocode/tendertracker/dao/BidDAO.java index a2ecabb..4b52863 100644 --- a/src/main/java/com/chlorocode/tendertracker/dao/BidDAO.java +++ b/src/main/java/com/chlorocode/tendertracker/dao/BidDAO.java @@ -5,10 +5,43 @@ import org.springframework.data.jpa.repository.Query; import org.springframework.stereotype.Repository; +import java.util.List; + +/** + * This DAO is used for Bid. + */ @Repository public interface BidDAO extends DataTablesRepository { + /** + * This method is used to find Bid by company and tender. + * + * @param companyId unique identifier of company + * @param tenderId unique identifier of tender + * @return Bid + * @see Bid + */ @Query("select b from Bid b where b.company.id = ?1 and b.tender.id = ?2") Bid findBidByCompanyAndTender(int companyId, int tenderId); + /** + * This method is used to find Bid by company. + * + * @param companyId unique identifier of company + * @return List + * @see Bid + */ + @Query("select b from Bid b where b.company.id = ?1") + List findBidByCompany(int companyId); + + /** + * This method is used to find Bid by tender. + * + * @param tenderId unique identifier of tender + * @return List + * @see Bid + */ + @Query("select b from Bid b where b.tender.id = ?1") + List findBidByTender(int tenderId); + } diff --git a/src/main/java/com/chlorocode/tendertracker/dao/BidDocumentDAO.java b/src/main/java/com/chlorocode/tendertracker/dao/BidDocumentDAO.java new file mode 100644 index 0000000..e24673a --- /dev/null +++ b/src/main/java/com/chlorocode/tendertracker/dao/BidDocumentDAO.java @@ -0,0 +1,13 @@ +package com.chlorocode.tendertracker.dao; + +import com.chlorocode.tendertracker.dao.entity.BidDocument; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +/** + * This DAO is used for Bid document. + */ +@Repository +public interface BidDocumentDAO extends JpaRepository { + +} diff --git a/src/main/java/com/chlorocode/tendertracker/dao/BidItemDAO.java b/src/main/java/com/chlorocode/tendertracker/dao/BidItemDAO.java new file mode 100644 index 0000000..4f595fd --- /dev/null +++ b/src/main/java/com/chlorocode/tendertracker/dao/BidItemDAO.java @@ -0,0 +1,12 @@ +package com.chlorocode.tendertracker.dao; + +import com.chlorocode.tendertracker.dao.entity.BidItem; +import org.springframework.data.jpa.repository.JpaRepository; + +/** + * Created by andy on 27/1/2018. + * This DAO is used for BidItem. + */ +public interface BidItemDAO extends JpaRepository { + +} diff --git a/src/main/java/com/chlorocode/tendertracker/dao/ClarificationDAO.java b/src/main/java/com/chlorocode/tendertracker/dao/ClarificationDAO.java index 5c1b2c7..940eaae 100644 --- a/src/main/java/com/chlorocode/tendertracker/dao/ClarificationDAO.java +++ b/src/main/java/com/chlorocode/tendertracker/dao/ClarificationDAO.java @@ -1,7 +1,6 @@ package com.chlorocode.tendertracker.dao; import com.chlorocode.tendertracker.dao.entity.Clarification; -import com.chlorocode.tendertracker.dao.entity.EvaluationCriteria; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.stereotype.Repository; @@ -10,10 +9,17 @@ /** * Created by andy on 8/8/2017. + * This DAO is used for Clarification. */ @Repository public interface ClarificationDAO extends JpaRepository { - + /** + * This method is used for finding tender clarification by tender id. + * + * @param tenderId unique identifier of tender. + * @return List + * @see Clarification + */ @Query("select r from Clarification r where r.tender.id = ?1 order by r.createdDate desc") List findClarificationByTenderId(int tenderId); diff --git a/src/main/java/com/chlorocode/tendertracker/dao/CodeValueDAO.java b/src/main/java/com/chlorocode/tendertracker/dao/CodeValueDAO.java index d84eda3..8dd917f 100644 --- a/src/main/java/com/chlorocode/tendertracker/dao/CodeValueDAO.java +++ b/src/main/java/com/chlorocode/tendertracker/dao/CodeValueDAO.java @@ -1,28 +1,36 @@ package com.chlorocode.tendertracker.dao; import com.chlorocode.tendertracker.dao.entity.CodeValue; -import com.chlorocode.tendertracker.dao.entity.Country; -import com.chlorocode.tendertracker.dao.entity.TenderCategory; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.stereotype.Repository; import java.util.List; +/** + * This DAO is used for finding predefined status, constant and combo box values(CodeValue). + */ @Repository public interface CodeValueDAO extends JpaRepository { + /** + * This method is used to find the list of code value by type. + * + * @param type type of the constant/status + * @return List + * @see CodeValue + */ List findByTypeOrderByOrderAsc(String type); + /** + * This method is used to get the description of CodeValue object. + * + * @param type type of the constant/status + * @param code code of the constant/status + * @return String + * @see CodeValue + */ @Query("select c.description from CodeValue c where c.type = ?1 and c.code = ?2") String getDescription(String type, int code); - @Query("select c from TenderCategory c order by c.name") - List getAllTenderCategories(); - - @Query("select c from TenderCategory c where c.id = ?1") - TenderCategory getTenderCategoryById(int id); - - @Query("select c from Country c order by c.name") - List getAllCountries(); } diff --git a/src/main/java/com/chlorocode/tendertracker/dao/CompanyDAO.java b/src/main/java/com/chlorocode/tendertracker/dao/CompanyDAO.java index 09a6b26..c2aaf3f 100644 --- a/src/main/java/com/chlorocode/tendertracker/dao/CompanyDAO.java +++ b/src/main/java/com/chlorocode/tendertracker/dao/CompanyDAO.java @@ -5,18 +5,64 @@ import org.springframework.data.jpa.repository.Query; import org.springframework.stereotype.Repository; +import java.util.Date; import java.util.List; +/** + * This DAO is used for CRUD operation of Company. + */ @Repository public interface CompanyDAO extends DataTablesRepository { + /** + * This method is used to find all companies that are waiting for approval. + * + * @return List + * @see Company + */ @Query("select c from Company c where c.status = 0") List findCompanyPendingApproval(); + /** + * This method is used to find companies by uen. + * + * @param uen uen of the company + * @return List + * @see Company + */ @Query("select c from Company c where c.uen = ?1") List findCompanyByUen(String uen); + /** + * This method is used to find companies by created userId. + * + * @param userId unique identifier of the company + * @return List + * @see Company + */ @Query("select c from Company c where c.createdBy = ?1") List findCompanyByCreatedBy(int userId); + /** + * This method is used to find companies that contain given string. + * + * @param name name of the company + * @return List + * @see Company + */ + @Query("select c from Company c where c.name LIKE CONCAT('%',?1,'%') and status = 1") + List findCompanyByName(String name); + + /** + * This method is used to get the company summary. + * + * @param startDate Date + * @param endDate Date + * @return List + */ + @Query(value = "select case when status=0 then 'Pending Approval' when status=1 then 'Approved' when status=2 " + + "then 'Rejected' end as Status, count(*) as Count from company where created_date >= ?1 " + + "and created_date <= ?2 group by status", + nativeQuery = true) + List getCompanySummary(Date startDate, Date endDate); } diff --git a/src/main/java/com/chlorocode/tendertracker/dao/CorrigendumDAO.java b/src/main/java/com/chlorocode/tendertracker/dao/CorrigendumDAO.java index 1846204..54d0856 100644 --- a/src/main/java/com/chlorocode/tendertracker/dao/CorrigendumDAO.java +++ b/src/main/java/com/chlorocode/tendertracker/dao/CorrigendumDAO.java @@ -7,9 +7,18 @@ import java.util.List; +/** + * This DAO is used for Corrigendum. + */ @Repository public interface CorrigendumDAO extends JpaRepository { - + /** + * This method is used to find the list of Corrigendum by tenderId. + * + * @param tenderId unique identifier of the tender + * @return List + * @see Corrigendum + */ @Query("select c from Corrigendum c where c.tender.id = ?1 order by c.createdDate desc") List findCorrigendumByTender(int tenderId); } diff --git a/src/main/java/com/chlorocode/tendertracker/dao/CorrigendumDocumentDAO.java b/src/main/java/com/chlorocode/tendertracker/dao/CorrigendumDocumentDAO.java index 4fa51ec..9eede28 100644 --- a/src/main/java/com/chlorocode/tendertracker/dao/CorrigendumDocumentDAO.java +++ b/src/main/java/com/chlorocode/tendertracker/dao/CorrigendumDocumentDAO.java @@ -4,6 +4,9 @@ import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; +/** + * This DAO used for CorrigendumDocument. + */ @Repository public interface CorrigendumDocumentDAO extends JpaRepository { diff --git a/src/main/java/com/chlorocode/tendertracker/dao/CountryDAO.java b/src/main/java/com/chlorocode/tendertracker/dao/CountryDAO.java new file mode 100644 index 0000000..d9d82d5 --- /dev/null +++ b/src/main/java/com/chlorocode/tendertracker/dao/CountryDAO.java @@ -0,0 +1,25 @@ +package com.chlorocode.tendertracker.dao; + +import com.chlorocode.tendertracker.dao.entity.Country; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.stereotype.Repository; + +import java.util.List; + +/** + * This DAO is used for Country. + */ +@Repository +public interface CountryDAO extends JpaRepository { + + /** + * This method is used to get all countries. + * + * @return List + * @see Country + */ + @Query("select c from Country c order by c.name") + List getAllCountries(); + +} diff --git a/src/main/java/com/chlorocode/tendertracker/dao/DocumentDAO.java b/src/main/java/com/chlorocode/tendertracker/dao/DocumentDAO.java deleted file mode 100644 index 19ae5d7..0000000 --- a/src/main/java/com/chlorocode/tendertracker/dao/DocumentDAO.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.chlorocode.tendertracker.dao; - -import com.chlorocode.tendertracker.dao.entity.Document; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -@Repository -public interface DocumentDAO extends JpaRepository { - -} diff --git a/src/main/java/com/chlorocode/tendertracker/dao/EvaluationCriteriaDAO.java b/src/main/java/com/chlorocode/tendertracker/dao/EvaluationCriteriaDAO.java index 90cf7f6..1e9468d 100644 --- a/src/main/java/com/chlorocode/tendertracker/dao/EvaluationCriteriaDAO.java +++ b/src/main/java/com/chlorocode/tendertracker/dao/EvaluationCriteriaDAO.java @@ -9,10 +9,17 @@ /** * Created by andy on 1/8/2017. + * This DAO used for EvaluationCriteria. */ @Repository public interface EvaluationCriteriaDAO extends JpaRepository { - + /** + * This method is used to find the EvaluationCriteria by tenderId. + * + * @param tenderId unique identifier of the tender + * @return List + * @see EvaluationCriteria + */ @Query("select r from EvaluationCriteria r where r.tender.id = ?1") List findEvaluationCriteriaByTender(int tenderId); } diff --git a/src/main/java/com/chlorocode/tendertracker/dao/EvaluationResultDAO.java b/src/main/java/com/chlorocode/tendertracker/dao/EvaluationResultDAO.java new file mode 100644 index 0000000..a64d41a --- /dev/null +++ b/src/main/java/com/chlorocode/tendertracker/dao/EvaluationResultDAO.java @@ -0,0 +1,55 @@ +package com.chlorocode.tendertracker.dao; + +import com.chlorocode.tendertracker.dao.entity.EvaluationResult; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.stereotype.Repository; + +import java.util.List; + +/** + * This DAO is used for EvaluationResult. + */ +@Repository +public interface EvaluationResultDAO extends JpaRepository { + /** + * This method is used to find the EvaluationResult by bid and evaluator. + * + * @param bidId unique identifier of the bid + * @param evaluatorId unique identifier of the evaluator + * @return List + * @see EvaluationResult + */ + @Query("select r from EvaluationResult r where r.bid.id = ?1 and r.evaluator.id = ?2") + List findEvaluationResultByBidAndEvaluator(int bidId, int evaluatorId); + + /** + * This method is used to get the average evaluation score of the bid. + * + * @param bidId unique identifier of the bid + * @return Double + */ + @Query("select avg(r.result) from EvaluationResult r where r.bid.id = ?1 and r.criteria.type = 1") + Double getBidAverageEvaluationScore(int bidId); + + /** + * This method is used to find the average evaluation score of bid criteria. + * + * @param bidId unique identifier of the bid + * @param criteriaId unique identifier of criteria + * @return Double + */ + @Query("select avg(r.result) from EvaluationResult r where r.bid.id = ?1 and r.criteria.id = ?2 and r.criteria.type = 1") + Double getBidCriteriaAverageEvaluationScore(int bidId, int criteriaId); + + /** + * This method is used to get the dual criteria evaluation count. + * + * @param bidId unique identifier of the bid + * @param criteriaId unique identifier of criteria + * @param result result of evaluation + * @return Integer + */ + @Query("select count(r) from EvaluationResult r where r.bid.id = ?1 and r.criteria.id = ?2 and r.result = ?3 and r.criteria.type = 2") + Integer getDualCriteriaEvaluationCount(int bidId, int criteriaId, int result); +} diff --git a/src/main/java/com/chlorocode/tendertracker/dao/ExternalTenderDAO.java b/src/main/java/com/chlorocode/tendertracker/dao/ExternalTenderDAO.java new file mode 100644 index 0000000..6a1d53c --- /dev/null +++ b/src/main/java/com/chlorocode/tendertracker/dao/ExternalTenderDAO.java @@ -0,0 +1,37 @@ +package com.chlorocode.tendertracker.dao; + +import com.chlorocode.tendertracker.dao.entity.ExternalTender; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.CrudRepository; + +import java.util.Date; + +/** + * Created by Kyaw Min Thu on 3/7/2017. + * This DAO is used for ExternalTender. + */ +public interface ExternalTenderDAO extends CrudRepository { + + /** + * This method is used to find the existing tender by refNo, title, sourceId, and companyName. + * + * @param refNo reference no + * @param title title of the external tender + * @param sourceId source id of the tender + * @param companyName company name + * @return ExternalTender + * @see ExternalTender + */ + @Query("select t from ExternalTender t where t.referenceNo = ?1 and t.title = ?2 and t.tenderSource = ?3 and t.companyName = ?4") + ExternalTender findExistingTender(String refNo, String title, String sourceId, String companyName); + + /** + * This method is used to close the external tender when the closingDate of such tender is less then current timestamp. + * + * @param currentDate current date of the system + */ + @Modifying + @Query("update ExternalTender t set t.status = 'CLOSED', t.lastUpdatedDate = ?1 where t.closingDate < ?1 and t.status = 'OPEN'") + void autoCloseExternalTender(Date currentDate); +} diff --git a/src/main/java/com/chlorocode/tendertracker/dao/ExternalTenderPagingDAO.java b/src/main/java/com/chlorocode/tendertracker/dao/ExternalTenderPagingDAO.java new file mode 100644 index 0000000..d1eb298 --- /dev/null +++ b/src/main/java/com/chlorocode/tendertracker/dao/ExternalTenderPagingDAO.java @@ -0,0 +1,11 @@ +package com.chlorocode.tendertracker.dao; + +import com.chlorocode.tendertracker.dao.entity.ExternalTender; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.data.repository.PagingAndSortingRepository; + +/** + * This DAO is used for showing External Tender by pagination. + */ +public interface ExternalTenderPagingDAO extends PagingAndSortingRepository, JpaSpecificationExecutor { +} diff --git a/src/main/java/com/chlorocode/tendertracker/dao/MilestoneDAO.java b/src/main/java/com/chlorocode/tendertracker/dao/MilestoneDAO.java new file mode 100644 index 0000000..2a424ee --- /dev/null +++ b/src/main/java/com/chlorocode/tendertracker/dao/MilestoneDAO.java @@ -0,0 +1,36 @@ +package com.chlorocode.tendertracker.dao; + +import com.chlorocode.tendertracker.dao.entity.Milestone; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.stereotype.Repository; + +import java.util.Date; +import java.util.List; + +/** + * Created by Kyaw Min Thu on 1/8/2017. + * This DAO is used for Milestone. + */ +@Repository +public interface MilestoneDAO extends JpaRepository { + /** + * This method is used to find the milestone by tenderId. + * + * @param tenderId unique identifier of the tender + * @return List + * @see Milestone + */ + @Query("select m from Milestone m where m.tender.id = ?1") + List findMilestoneByTender(int tenderId); + + /** + * This method is used to find the approach mile stone by due date. + * + * @param dueDate target date + * @return List + * @see Milestone + */ + @Query("select m from Milestone m where m.dueDate < ?1 and m.notifyStatus=0") + List findApproachMilestone(Date dueDate); +} diff --git a/src/main/java/com/chlorocode/tendertracker/dao/ProductClarificationDAO.java b/src/main/java/com/chlorocode/tendertracker/dao/ProductClarificationDAO.java new file mode 100644 index 0000000..06e6330 --- /dev/null +++ b/src/main/java/com/chlorocode/tendertracker/dao/ProductClarificationDAO.java @@ -0,0 +1,26 @@ +package com.chlorocode.tendertracker.dao; + +import com.chlorocode.tendertracker.dao.entity.ProductClarification; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.stereotype.Repository; + +import java.util.List; + +/** + * Created by andy on 18/1/2018. + * This DAO is used for Product Clarification. + */ +@Repository +public interface ProductClarificationDAO extends JpaRepository { + + /** + * This method is used for finding clarification by product code. + * @param prodId product code + * @return List + * @see ProductClarification + */ + @Query("select r from ProductClarification r where r.product.productCode = ?1 order by r.createdDate desc") + List findClarificationByProdId(int prodId); +} + diff --git a/src/main/java/com/chlorocode/tendertracker/dao/ProductDAO.java b/src/main/java/com/chlorocode/tendertracker/dao/ProductDAO.java new file mode 100644 index 0000000..4a6ec96 --- /dev/null +++ b/src/main/java/com/chlorocode/tendertracker/dao/ProductDAO.java @@ -0,0 +1,14 @@ +package com.chlorocode.tendertracker.dao; + +import com.chlorocode.tendertracker.dao.entity.Product; +import org.springframework.data.jpa.datatables.repository.DataTablesRepository; +import org.springframework.stereotype.Repository; + +/** + * DAO class for Product entity. + * This class extends DataTableRepository so that it can output the entity into DataTables. + */ +@Repository +public interface ProductDAO extends DataTablesRepository { + +} diff --git a/src/main/java/com/chlorocode/tendertracker/dao/ProductDataClarificationDAO.java b/src/main/java/com/chlorocode/tendertracker/dao/ProductDataClarificationDAO.java new file mode 100644 index 0000000..a1e7dbc --- /dev/null +++ b/src/main/java/com/chlorocode/tendertracker/dao/ProductDataClarificationDAO.java @@ -0,0 +1,14 @@ +package com.chlorocode.tendertracker.dao; + +import com.chlorocode.tendertracker.dao.entity.ProductClarification; +import org.springframework.data.jpa.datatables.repository.DataTablesRepository; +import org.springframework.stereotype.Repository; + +/** + * Created by andy on 20/1/2018. + * This class extends DataTableRepository so that it can output the entity into DataTables. + */ +@Repository +public interface ProductDataClarificationDAO extends DataTablesRepository { + +} diff --git a/src/main/java/com/chlorocode/tendertracker/dao/ProductPagingDAO.java b/src/main/java/com/chlorocode/tendertracker/dao/ProductPagingDAO.java new file mode 100644 index 0000000..67c487f --- /dev/null +++ b/src/main/java/com/chlorocode/tendertracker/dao/ProductPagingDAO.java @@ -0,0 +1,12 @@ +package com.chlorocode.tendertracker.dao; + +import com.chlorocode.tendertracker.dao.entity.Product; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.data.repository.PagingAndSortingRepository; + +/** + * DAO class for Product with Paging and Sorting feature. + */ +public interface ProductPagingDAO extends PagingAndSortingRepository, JpaSpecificationExecutor { + +} diff --git a/src/main/java/com/chlorocode/tendertracker/dao/RoleUserDAO.java b/src/main/java/com/chlorocode/tendertracker/dao/RoleUserDAO.java index 3f40cf5..8934b85 100644 --- a/src/main/java/com/chlorocode/tendertracker/dao/RoleUserDAO.java +++ b/src/main/java/com/chlorocode/tendertracker/dao/RoleUserDAO.java @@ -3,20 +3,33 @@ import com.chlorocode.tendertracker.dao.entity.RoleUser; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; -import java.util.List; - /** * Created by andy on 22/7/2017. + * This DAO is used for User Role. */ @Repository public interface RoleUserDAO extends JpaRepository { + /** + * This method is used to find the user role by userId, companyId and roleId. + * + * @param userId unique identifier of user + * @param companyId unique identifier of company + * @param roleId unique identifier of role + * @return Integer + */ @Query("select distinct r.roleId from RoleUser r where r.userId =?1 and r.companyId =?2 and r.roleId =?3") Integer findUserRoleId(int userId, int companyId, int roleId); + /** + * This method is used to find the user role by id. + * + * @param id unique identifier of user role + * @return RoleUser + * @see RoleUser + */ @Query("select r from RoleUser r where r.id=?1") RoleUser findUserRoleById(int id); } diff --git a/src/main/java/com/chlorocode/tendertracker/dao/TenderAppealDAO.java b/src/main/java/com/chlorocode/tendertracker/dao/TenderAppealDAO.java new file mode 100644 index 0000000..b364182 --- /dev/null +++ b/src/main/java/com/chlorocode/tendertracker/dao/TenderAppealDAO.java @@ -0,0 +1,25 @@ +package com.chlorocode.tendertracker.dao; + +import com.chlorocode.tendertracker.dao.entity.TenderAppeal; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.stereotype.Repository; + +import java.util.List; + +/** + * DAO class for TenderAppeal entity. + */ +@Repository +public interface TenderAppealDAO extends JpaRepository { + + /** + * This method is used to find TenderAppeal by tenderId and companyId. + * + * @param tenderId unique identifier of the tender + * @param companyId unique identifier of the company + * @return list of TenderAppeal + */ + @Query("select r from TenderAppeal r where r.tender.id = ?1 and r.company.id=?2 order by r.createdDate desc") + List findTenderAppealsBy(int tenderId, int companyId); +} diff --git a/src/main/java/com/chlorocode/tendertracker/dao/TenderAwardDAO.java b/src/main/java/com/chlorocode/tendertracker/dao/TenderAwardDAO.java new file mode 100644 index 0000000..2e2d6ac --- /dev/null +++ b/src/main/java/com/chlorocode/tendertracker/dao/TenderAwardDAO.java @@ -0,0 +1,13 @@ +package com.chlorocode.tendertracker.dao; + +import com.chlorocode.tendertracker.dao.entity.TenderAward; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +/** + * This DAO is used for Tender Award. + */ +@Repository +public interface TenderAwardDAO extends JpaRepository { + +} diff --git a/src/main/java/com/chlorocode/tendertracker/dao/TenderBookmarkDAO.java b/src/main/java/com/chlorocode/tendertracker/dao/TenderBookmarkDAO.java index 109aab5..09fb8b2 100644 --- a/src/main/java/com/chlorocode/tendertracker/dao/TenderBookmarkDAO.java +++ b/src/main/java/com/chlorocode/tendertracker/dao/TenderBookmarkDAO.java @@ -7,15 +7,40 @@ import java.util.List; +/** + * This DAO is used for TenderBookmark. + */ @Repository public interface TenderBookmarkDAO extends JpaRepository { + /** + * This method is used for find the tender bookmark by tenderId and userId. + * + * @param tenderId unique identifier of tender + * @param userId unique identifier of user + * @return TenderBookmark + * @see TenderBookmark + */ @Query("select t from TenderBookmark t where t.tender.id = ?1 and t.user.id = ?2") TenderBookmark findTenderBookmarkByUserAndTender(int tenderId, int userId); + /** + * This method is used for find the tender bookmark by userId. + * + * @param userId unique identifier of user + * @return List + * @see TenderBookmark + */ @Query("select t from TenderBookmark t where t.user.id = ?1") List findTenderBookmarkByUserId(int userId); + /** + * This method is used for find the tender bookmark by tenderId. + * + * @param tenderId unique identifier of tender + * @return List + * @see TenderBookmark + */ @Query("select t from TenderBookmark t where t.tender.id = ?1") List findTenderBookmarkByTender(int tenderId); } diff --git a/src/main/java/com/chlorocode/tendertracker/dao/TenderCategoryDAO.java b/src/main/java/com/chlorocode/tendertracker/dao/TenderCategoryDAO.java new file mode 100644 index 0000000..f7891d4 --- /dev/null +++ b/src/main/java/com/chlorocode/tendertracker/dao/TenderCategoryDAO.java @@ -0,0 +1,35 @@ +package com.chlorocode.tendertracker.dao; + +import com.chlorocode.tendertracker.dao.entity.TenderCategory; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.stereotype.Repository; + +import java.util.List; + +/** + * This DAO is used for TenderCategory. + */ +@Repository +public interface TenderCategoryDAO extends JpaRepository { + + /** + * This method is used to get all tender categories. + * + * @return List + * @see TenderCategory + */ + @Query("select c from TenderCategory c order by c.name") + List getAllTenderCategories(); + + /** + * This method is used to get tender category by id. + * + * @param id unique identifier of TenderCategory + * @return TenderCategory + * @see TenderCategory + */ + @Query("select c from TenderCategory c where c.id = ?1") + TenderCategory getTenderCategoryById(int id); + +} diff --git a/src/main/java/com/chlorocode/tendertracker/dao/TenderCategorySubscriptionDAO.java b/src/main/java/com/chlorocode/tendertracker/dao/TenderCategorySubscriptionDAO.java index 836749e..5f011e1 100644 --- a/src/main/java/com/chlorocode/tendertracker/dao/TenderCategorySubscriptionDAO.java +++ b/src/main/java/com/chlorocode/tendertracker/dao/TenderCategorySubscriptionDAO.java @@ -8,16 +8,38 @@ import java.util.List; +/** + * This DAO used for TenderCategorySubscription. + */ @Repository public interface TenderCategorySubscriptionDAO extends JpaRepository { + /** + * This method is used to delete the existing subscription by userId. + * + * @param userId unique identifier of user + */ @Modifying @Query("delete from TenderCategorySubscription s where s.user.id = ?1") void removeExistingSubscription(int userId); + /** + * This method is used to find the user subscription by userId. + * + * @param userId unique identifier of user + * @return List + * @see TenderCategorySubscription + */ @Query("select s from TenderCategorySubscription s where s.user.id = ?1") List findUserSubscription(int userId); + /** + * This method is used to find the user subscription by categoryId. + * + * @param categoryId unique identifier of category + * @return List + * @see TenderCategorySubscription + */ @Query("select s from TenderCategorySubscription s where s.tenderCategory.id = ?1") List findUserSubscriptionByTenderCategory(int categoryId); } diff --git a/src/main/java/com/chlorocode/tendertracker/dao/TenderDAO.java b/src/main/java/com/chlorocode/tendertracker/dao/TenderDAO.java index a51e2d2..5a77e8a 100644 --- a/src/main/java/com/chlorocode/tendertracker/dao/TenderDAO.java +++ b/src/main/java/com/chlorocode/tendertracker/dao/TenderDAO.java @@ -1,18 +1,131 @@ package com.chlorocode.tendertracker.dao; import com.chlorocode.tendertracker.dao.entity.Tender; +import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.datatables.repository.DataTablesRepository; +import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import org.springframework.stereotype.Repository; +import java.util.Date; import java.util.List; +/** + * This DAO used for Tender. + */ @Repository public interface TenderDAO extends DataTablesRepository { + /** + * This method is used to get the tender stqatus statistic by company. + * + * @param companyId unique identifier of company + * @return List + */ @Query(value = "SELECT c.description, count(*) as count " + "FROM tender t inner join code_value c on t.status = c.code and c.type = 'tender_status' " + "where t.company_id = ?1 " + "group by c.description", nativeQuery = true) List getTenderStatusStatisticByCompany(int companyId); + + /** + * This method is used to find all tenders by date range. + * + * @param openDateFrom start of open date range + * @param openDateTo end of open date range + * @param closeDateFrom start of close date range + * @param closeDateTo end of close date range + * @param category category of the tender + * @param status status of the tender + * @return List + */ + @Query(value = "select t.ref_no, t.title, c1.description as tender_type, tc.name, open_date, closed_date, c2.description as status " + + "from tender t, tender_category tc, code_value c1, code_value c2 " + + "where tc.id = t.tender_category_id and t.tender_type = c1.code and c1.type = 'tender_type' " + + "and t.status = c2.code and c2.type = 'tender_status' and t.open_date >= ?1 and t.open_date <= ?2 " + + "and t.closed_date >= ?3 and t.closed_date <= ?4 " + + "and t.tender_category_id = ?5 and t.status = ?6 ", + nativeQuery = true) + List findAllByDateRange(Date openDateFrom, Date openDateTo, + Date closeDateFrom, Date closeDateTo, + String category, String status); + + /** + * This method is used to close the tender which closed date is less than current timestamp. + * + * @param currentDate current date of the system + */ + @Modifying + @Query("update Tender t set t.status = 2, t.lastUpdatedBy = -1, t.lastUpdatedDate = ?1 where t.closedDate < ?1 and t.status = 1") + void autoCloseTender(Date currentDate); + + /** + * This method is used to find the tenders which should be close. + * + * @param currentDate current date of the system + * @return List + * @see Tender + */ + @Query(value = "select t from Tender t where t.closedDate < ?1 and t.status = 1") + List findClosingTender(Date currentDate); + + /** + * This method is used to close the tender by tender id. + * @param id unique identifier of tender + * @param currentDate current date of the system + */ + @Modifying + @Query("update Tender t set t.status = 2, t.lastUpdatedBy = -1, t.lastUpdatedDate = ?2 where t.id = ?1") + void closeTender(int id, Date currentDate); + + /** + * This method is used to get the number of visit by tenderId. + * + * @param tenderId unique identifier of tender + * @return Integer + */ + @Query("select count(v) from Tender t join t.tenderVisits v where t.id = ?1") + Integer getNumberOfVisit(int tenderId); + + /** + * This method is used to get the number of unique visit by tenderId. + * + * @param tenderId unique identifier of tender + * @return Integer + */ + @Query("select count(distinct v.ipAddress) from Tender t join t.tenderVisits v where t.id = ?1") + Integer getNumberOfUniqueVisit(int tenderId); + + /** + * This method is used to find the top country visitor. + * + * @param tenderId unique identifier of tender + * @param pageable Pageable + * @return List + */ + @Query("select v.country, count(v) from Tender t join t.tenderVisits v where t.id = ?1 group by v.country order by count(v) desc") + List getTopCountryVisitor(int tenderId, Pageable pageable); + + /** + * This method is used to find the tender summary range of the date. + * + * @param startDate open_date of the tender must be greater than or equal to startDate + * @param endDate open_date of the tender must be less than or equal to startDate + * @return List + */ + @Query(value = "select case when status=1 then 'Open' when status=2 then 'Closed' else 'Others' end as Status, " + + "count(*) as Count from tender where open_date >= ?1 and open_date <= ?2 group by status", + nativeQuery = true) + List getTenderSummary(Date startDate, Date endDate); + + /** + * This method is used to find the list of invited tender by companyId. + * + * @param companyId unique identifier of company + * @return List + * @see Tender + */ + @Query(value = "select distinct t from Tender t join t.invitedCompanies c where c.id = ?1") + List findTenderByInvitedCompany(int companyId); + } diff --git a/src/main/java/com/chlorocode/tendertracker/dao/TenderDataAppealDAO.java b/src/main/java/com/chlorocode/tendertracker/dao/TenderDataAppealDAO.java new file mode 100644 index 0000000..f2674f6 --- /dev/null +++ b/src/main/java/com/chlorocode/tendertracker/dao/TenderDataAppealDAO.java @@ -0,0 +1,11 @@ +package com.chlorocode.tendertracker.dao; + +import com.chlorocode.tendertracker.dao.entity.TenderAppeal; +import org.springframework.data.jpa.datatables.repository.DataTablesRepository; + +/** + * Created by andy on 16/1/2018. + * This class extends DataTableRepository so that it can output the entity into DataTables. + */ +public interface TenderDataAppealDAO extends DataTablesRepository { +} diff --git a/src/main/java/com/chlorocode/tendertracker/dao/TenderDataClarificationDAO.java b/src/main/java/com/chlorocode/tendertracker/dao/TenderDataClarificationDAO.java index 24146a4..76ecf78 100644 --- a/src/main/java/com/chlorocode/tendertracker/dao/TenderDataClarificationDAO.java +++ b/src/main/java/com/chlorocode/tendertracker/dao/TenderDataClarificationDAO.java @@ -1,12 +1,12 @@ package com.chlorocode.tendertracker.dao; import com.chlorocode.tendertracker.dao.entity.Clarification; -import com.chlorocode.tendertracker.dao.entity.Tender; import org.springframework.data.jpa.datatables.repository.DataTablesRepository; import org.springframework.stereotype.Repository; /** * Created by andy on 8/8/2017. + * This class extends DataTableRepository so that it can output the entity into DataTables. */ @Repository public interface TenderDataClarificationDAO extends DataTablesRepository { diff --git a/src/main/java/com/chlorocode/tendertracker/dao/TenderDocumentDAO.java b/src/main/java/com/chlorocode/tendertracker/dao/TenderDocumentDAO.java index 29127df..b02b705 100644 --- a/src/main/java/com/chlorocode/tendertracker/dao/TenderDocumentDAO.java +++ b/src/main/java/com/chlorocode/tendertracker/dao/TenderDocumentDAO.java @@ -4,6 +4,9 @@ import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; +/** + * This DAO is used for Tender Document. + */ @Repository public interface TenderDocumentDAO extends JpaRepository { diff --git a/src/main/java/com/chlorocode/tendertracker/dao/TenderItemDAO.java b/src/main/java/com/chlorocode/tendertracker/dao/TenderItemDAO.java index 5d3b933..f9c6667 100644 --- a/src/main/java/com/chlorocode/tendertracker/dao/TenderItemDAO.java +++ b/src/main/java/com/chlorocode/tendertracker/dao/TenderItemDAO.java @@ -2,9 +2,23 @@ import com.chlorocode.tendertracker.dao.entity.TenderItem; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; import org.springframework.stereotype.Repository; +/** + * This DAO is used for Tender Item. + */ @Repository public interface TenderItemDAO extends JpaRepository { + /** + * This method is used to find the TenderItem by tenderId and sort. + * + * @param tenderId unique identifier of tender + * @param sort sort pattern code + * @return TenderItem + * @see TenderItem + */ + @Query(value = "SELECT ti FROM TenderItem ti JOIN ti.tender t WHERE t.id = ?1 AND ti.sort = ?2") + TenderItem getTenderItemBySort(int tenderId, int sort); } diff --git a/src/main/java/com/chlorocode/tendertracker/dao/TenderPagingDAO.java b/src/main/java/com/chlorocode/tendertracker/dao/TenderPagingDAO.java index b633611..f612fc2 100644 --- a/src/main/java/com/chlorocode/tendertracker/dao/TenderPagingDAO.java +++ b/src/main/java/com/chlorocode/tendertracker/dao/TenderPagingDAO.java @@ -4,8 +4,8 @@ import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.repository.PagingAndSortingRepository; -import java.util.Date; -import java.util.List; - +/** + * This DAO is used to show the tender in search screen by paging and sorting features. + */ public interface TenderPagingDAO extends PagingAndSortingRepository, JpaSpecificationExecutor { } diff --git a/src/main/java/com/chlorocode/tendertracker/dao/TenderVisitDAO.java b/src/main/java/com/chlorocode/tendertracker/dao/TenderVisitDAO.java new file mode 100644 index 0000000..c6b1878 --- /dev/null +++ b/src/main/java/com/chlorocode/tendertracker/dao/TenderVisitDAO.java @@ -0,0 +1,11 @@ +package com.chlorocode.tendertracker.dao; + +import com.chlorocode.tendertracker.dao.entity.TenderVisit; +import org.springframework.data.jpa.repository.JpaRepository; + +/** + * This DAO is used for TenderVisit. + */ +public interface TenderVisitDAO extends JpaRepository { + +} diff --git a/src/main/java/com/chlorocode/tendertracker/dao/UenEntityDAO.java b/src/main/java/com/chlorocode/tendertracker/dao/UenEntityDAO.java index 0c39cf0..c7dc8eb 100644 --- a/src/main/java/com/chlorocode/tendertracker/dao/UenEntityDAO.java +++ b/src/main/java/com/chlorocode/tendertracker/dao/UenEntityDAO.java @@ -6,9 +6,17 @@ /** * Created by andy on 16/8/2017. + * This DAO is used for UenEntity. */ public interface UenEntityDAO extends JpaRepository { + /** + * This method is used to find the UenEntity by uen. + * + * @param uen uen of the UenEntity + * @return UenEntity + * @see UenEntity + */ @Query("select r from UenEntity r where r.uen = ?1") UenEntity findByUen(String uen); } diff --git a/src/main/java/com/chlorocode/tendertracker/dao/UserDAO.java b/src/main/java/com/chlorocode/tendertracker/dao/UserDAO.java index 414cf65..5144168 100644 --- a/src/main/java/com/chlorocode/tendertracker/dao/UserDAO.java +++ b/src/main/java/com/chlorocode/tendertracker/dao/UserDAO.java @@ -6,9 +6,19 @@ import java.util.Optional; +/** + * This DAO is used for User. + */ @Repository public interface UserDAO extends JpaRepository { + /** + * This method is used to find user by email. + * + * @param email email address of user + * @return Optional + * @see User + */ Optional findOneByEmail(String email); } diff --git a/src/main/java/com/chlorocode/tendertracker/dao/UserDataDAO.java b/src/main/java/com/chlorocode/tendertracker/dao/UserDataDAO.java index fafb869..e959779 100644 --- a/src/main/java/com/chlorocode/tendertracker/dao/UserDataDAO.java +++ b/src/main/java/com/chlorocode/tendertracker/dao/UserDataDAO.java @@ -4,6 +4,9 @@ import org.springframework.data.jpa.datatables.repository.DataTablesRepository; import org.springframework.stereotype.Repository; +/** + * This class extends DataTableRepository so that it can output the entity into DataTables. + */ @Repository public interface UserDataDAO extends DataTablesRepository { } diff --git a/src/main/java/com/chlorocode/tendertracker/dao/UserRoleDAO.java b/src/main/java/com/chlorocode/tendertracker/dao/UserRoleDAO.java index de6ab82..9a77882 100644 --- a/src/main/java/com/chlorocode/tendertracker/dao/UserRoleDAO.java +++ b/src/main/java/com/chlorocode/tendertracker/dao/UserRoleDAO.java @@ -9,21 +9,80 @@ import java.util.List; +/** + * This DAO is used for UserRole. + */ @Repository public interface UserRoleDAO extends JpaRepository { + /** + * This method is used for finding role by roleId. + * + * @param roleId unique identifier of role + * @return Role + * @see Role + */ @Query("select r from Role r where r.id = ?1") Role findRoleById(int roleId); + /** + * This method is used to find the role by userId and companyId. + * + * @param userId unique identifier of user + * @param companyId unique identifier of company + * @return List + * @see Role + */ @Query("select r from UserRole ur join ur.role r where ur.user.id = ?1 and ur.company.id = ?2") List findRoleForCompanyUser(int userId, int companyId); + /** + * This method is used to find the UserRole by userId and companyId. + * + * @param userId unique identifier of user + * @param companyId unique identifier of company + * @return List + * @see UserRole + */ @Query("select ur from UserRole ur where ur.user.id = ?1 and ur.company.id = ?2") List findUserRoleByUserAndCompany(int userId, int companyId); + /** + * This method is used to find the name of UserRole by userId. + * + * @param userId unique identifier of user + * @return List + */ @Query("select distinct r.name from UserRole ur join ur.role r where ur.user.id = ?1") List findUniqueUserRole(int userId); + /** + * This method is used to find administrator company for user. + * + * @param userId unique identifier of user + * @return List + * @see Company + */ @Query("select distinct c from UserRole ur join ur.company c where ur.user.id = ?1 and c.status = 1 order by c.name") List findUserAdministeredCompany(int userId); + + /** + * This method is used to find the admin of the company. + * + * @param companyId unique identifier of company + * @return List + * @see UserRole + */ + @Query("select ur from UserRole ur where ur.company.id = ?1 and ur.role.id = 2") + List findCompanyAdminUserRole(int companyId); + + /** + * This method is used to find the all users of the company. + * + * @param companyId unique identifier of company + * @return List + * @see UserRole + */ + @Query("select ur from UserRole ur where ur.company.id = ?1") + List findUserRoleByCompany(int companyId); } diff --git a/src/main/java/com/chlorocode/tendertracker/dao/dto/AlertDTO.java b/src/main/java/com/chlorocode/tendertracker/dao/dto/AlertDTO.java index 507a721..73d84a2 100644 --- a/src/main/java/com/chlorocode/tendertracker/dao/dto/AlertDTO.java +++ b/src/main/java/com/chlorocode/tendertracker/dao/dto/AlertDTO.java @@ -5,6 +5,9 @@ import java.util.LinkedList; import java.util.List; +/** + * Data transfer object for alert message box. + */ public class AlertDTO { public enum AlertType { diff --git a/src/main/java/com/chlorocode/tendertracker/dao/dto/ChangePasswordDTO.java b/src/main/java/com/chlorocode/tendertracker/dao/dto/ChangePasswordDTO.java index d455721..d4ee157 100644 --- a/src/main/java/com/chlorocode/tendertracker/dao/dto/ChangePasswordDTO.java +++ b/src/main/java/com/chlorocode/tendertracker/dao/dto/ChangePasswordDTO.java @@ -7,6 +7,7 @@ /** * Kyaw Min Thu + * Data transfer object for change password. */ public class ChangePasswordDTO { diff --git a/src/main/java/com/chlorocode/tendertracker/dao/dto/CompanyInfoDTO.java b/src/main/java/com/chlorocode/tendertracker/dao/dto/CompanyInfoDTO.java index 3d2c76b..bc21474 100644 --- a/src/main/java/com/chlorocode/tendertracker/dao/dto/CompanyInfoDTO.java +++ b/src/main/java/com/chlorocode/tendertracker/dao/dto/CompanyInfoDTO.java @@ -2,8 +2,9 @@ import org.hibernate.validator.constraints.NotBlank; -import javax.validation.constraints.NotNull; - +/** + * Data transfer object for company information. + */ public class CompanyInfoDTO { private int id; private String name; diff --git a/src/main/java/com/chlorocode/tendertracker/dao/dto/CompanyRegistrationDTO.java b/src/main/java/com/chlorocode/tendertracker/dao/dto/CompanyRegistrationDTO.java index 26d50f3..b258281 100644 --- a/src/main/java/com/chlorocode/tendertracker/dao/dto/CompanyRegistrationDTO.java +++ b/src/main/java/com/chlorocode/tendertracker/dao/dto/CompanyRegistrationDTO.java @@ -4,12 +4,14 @@ import javax.validation.constraints.NotNull; +/** + * Data transfer object for company registration. + */ public class CompanyRegistrationDTO { @NotBlank(message = "Name is required") private String name; - @NotBlank(message = "GST Registration No is required") private String gstRegNo; @NotBlank(message = "UEN is required") diff --git a/src/main/java/com/chlorocode/tendertracker/dao/dto/CompanyRegistrationDetailsDTO.java b/src/main/java/com/chlorocode/tendertracker/dao/dto/CompanyRegistrationDetailsDTO.java index f1261f9..9c74db8 100644 --- a/src/main/java/com/chlorocode/tendertracker/dao/dto/CompanyRegistrationDetailsDTO.java +++ b/src/main/java/com/chlorocode/tendertracker/dao/dto/CompanyRegistrationDetailsDTO.java @@ -4,6 +4,9 @@ import java.util.Date; +/** + * Data transfer object for company registration detail. + */ public class CompanyRegistrationDetailsDTO { private int id; private String name; @@ -22,6 +25,33 @@ public class CompanyRegistrationDetailsDTO { private Date applicationDate; private String mailingAddress; private String principleActivity; + private String status; + private boolean active; + private String companyStatus; + + public String getCompanyStatus() { + return companyStatus; + } + + public void setCompanyStatus(String companyStatus) { + this.companyStatus = companyStatus; + } + + public boolean isActive() { + return active; + } + + public void setActive(boolean active) { + this.active = active; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } public String getMailingAddress() { return mailingAddress; diff --git a/src/main/java/com/chlorocode/tendertracker/dao/dto/CompanyUserAddDTO.java b/src/main/java/com/chlorocode/tendertracker/dao/dto/CompanyUserAddDTO.java index ea7d695..5121239 100644 --- a/src/main/java/com/chlorocode/tendertracker/dao/dto/CompanyUserAddDTO.java +++ b/src/main/java/com/chlorocode/tendertracker/dao/dto/CompanyUserAddDTO.java @@ -5,6 +5,9 @@ import java.util.LinkedList; import java.util.List; +/** + * Data transfer object for company user add. + */ public class CompanyUserAddDTO { @NotBlank(message = "Email is required") private String email; diff --git a/src/main/java/com/chlorocode/tendertracker/dao/dto/CorrigendumCreateDTO.java b/src/main/java/com/chlorocode/tendertracker/dao/dto/CorrigendumCreateDTO.java index 5074693..8828fb3 100644 --- a/src/main/java/com/chlorocode/tendertracker/dao/dto/CorrigendumCreateDTO.java +++ b/src/main/java/com/chlorocode/tendertracker/dao/dto/CorrigendumCreateDTO.java @@ -5,6 +5,9 @@ import java.util.List; +/** + * Data transfer object for corrigendum create. + */ public class CorrigendumCreateDTO { private int tenderId; diff --git a/src/main/java/com/chlorocode/tendertracker/dao/dto/CorrigendumUpdateDTO.java b/src/main/java/com/chlorocode/tendertracker/dao/dto/CorrigendumUpdateDTO.java index e670ea6..7f46f48 100644 --- a/src/main/java/com/chlorocode/tendertracker/dao/dto/CorrigendumUpdateDTO.java +++ b/src/main/java/com/chlorocode/tendertracker/dao/dto/CorrigendumUpdateDTO.java @@ -5,6 +5,9 @@ import java.util.List; +/** + * Data transfer object for corrigendum update. + */ public class CorrigendumUpdateDTO { private int id; diff --git a/src/main/java/com/chlorocode/tendertracker/dao/dto/EvaluateCriteriaDTO.java b/src/main/java/com/chlorocode/tendertracker/dao/dto/EvaluateCriteriaDTO.java index 5c6619b..d0ee76c 100644 --- a/src/main/java/com/chlorocode/tendertracker/dao/dto/EvaluateCriteriaDTO.java +++ b/src/main/java/com/chlorocode/tendertracker/dao/dto/EvaluateCriteriaDTO.java @@ -4,6 +4,7 @@ /** * Created by andy on 2/8/2017. + * Data transfer object for company information. */ public class EvaluateCriteriaDTO { diff --git a/src/main/java/com/chlorocode/tendertracker/dao/dto/ForgotPasswordDTO.java b/src/main/java/com/chlorocode/tendertracker/dao/dto/ForgotPasswordDTO.java index 16399ff..9bf7414 100644 --- a/src/main/java/com/chlorocode/tendertracker/dao/dto/ForgotPasswordDTO.java +++ b/src/main/java/com/chlorocode/tendertracker/dao/dto/ForgotPasswordDTO.java @@ -3,8 +3,9 @@ import org.hibernate.validator.constraints.Email; import org.hibernate.validator.constraints.NotBlank; -import javax.annotation.MatchesPattern; - +/** + * Data transfer object for forgot password. + */ public class ForgotPasswordDTO { @NotBlank(message = "Email address must not be empty.") diff --git a/src/main/java/com/chlorocode/tendertracker/dao/dto/LoginDTO.java b/src/main/java/com/chlorocode/tendertracker/dao/dto/LoginDTO.java index 187ed5a..b46068d 100644 --- a/src/main/java/com/chlorocode/tendertracker/dao/dto/LoginDTO.java +++ b/src/main/java/com/chlorocode/tendertracker/dao/dto/LoginDTO.java @@ -2,6 +2,9 @@ import org.hibernate.validator.constraints.NotBlank; +/** + * Data transfer object for login. + */ public class LoginDTO { @NotBlank diff --git a/src/main/java/com/chlorocode/tendertracker/dao/dto/MilestoneDTO.java b/src/main/java/com/chlorocode/tendertracker/dao/dto/MilestoneDTO.java new file mode 100644 index 0000000..f8e7fcf --- /dev/null +++ b/src/main/java/com/chlorocode/tendertracker/dao/dto/MilestoneDTO.java @@ -0,0 +1,64 @@ +package com.chlorocode.tendertracker.dao.dto; + +import org.hibernate.validator.constraints.NotBlank; + +import javax.validation.constraints.NotNull; +import java.util.Date; + +/** + * Created by Kyaw Min Thu on 6/1/2018. + * Data transfer object for Milestone. + */ +public class MilestoneDTO { + + private int id; + private int tenderId; + + @NotBlank(message = "Please specify milestone description") + private String description; + + @NotNull(message = "Milestone Due Date is required") + private Date dueDate; + + private int status; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public int getTenderId() { + return tenderId; + } + + public void setTenderId(int tenderId) { + this.tenderId = tenderId; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public Date getDueDate() { + return dueDate; + } + + public void setDueDate(Date dueDate) { + this.dueDate = dueDate; + } + + public int getStatus() { + return status; + } + + public void setStatus(int status) { + this.status = status; + } +} diff --git a/src/main/java/com/chlorocode/tendertracker/dao/dto/ProcurementReportDTO.java b/src/main/java/com/chlorocode/tendertracker/dao/dto/ProcurementReportDTO.java new file mode 100644 index 0000000..7b7e81e --- /dev/null +++ b/src/main/java/com/chlorocode/tendertracker/dao/dto/ProcurementReportDTO.java @@ -0,0 +1,81 @@ +package com.chlorocode.tendertracker.dao.dto; + +import java.util.Date; + +/** + * Created by Rag on 17-Dec-17. + * Data transfer object for procurement report. + */ +public class ProcurementReportDTO { + + private String refNum; + private String tenderName; + private String tenderType; + private String tenderCategory; + private Date openingDate; + private Date closingDate; + private String tenderStatus; + + public ProcurementReportDTO(String refNum, String tenderName, String tenderType, String tenderCategory, Date openingDate, Date closingDate, String tenderStatus) { + this.refNum = refNum; + this.tenderName = tenderName; + this.tenderType = tenderType; + this.tenderCategory = tenderCategory; + this.openingDate = openingDate; + this.closingDate = closingDate; + this.tenderStatus = tenderStatus; + } + + public String getRefNum() { return refNum; } + + public void setRefNum(String refNum) { this.refNum = refNum; } + + public String getTenderName() { + return tenderName; + } + + public void setTenderName(String tenderName) { + this.tenderName = tenderName; + } + + public String getTenderType() { + return tenderType; + } + + public void setTenderType(String tenderType) { + this.tenderType = tenderType; + } + + public String getTenderCategory() { + return tenderCategory; + } + + public void setTenderCategory(String tenderCategory) { + this.tenderCategory = tenderCategory; + } + + public Date getOpeningDate() { + return openingDate; + } + + public void setOpeningDate(Date openingDate) { + this.openingDate = openingDate; + } + + public Date getClosingDate() { + return closingDate; + } + + public void setClosingDate(Date closingDate) { + this.closingDate = closingDate; + } + + public String getTenderStatus() { + return tenderStatus; + } + + public void setTenderStatus(String tenderStatus) { + this.tenderStatus = tenderStatus; + } + +} diff --git a/src/main/java/com/chlorocode/tendertracker/dao/dto/ProductCreateDTO.java b/src/main/java/com/chlorocode/tendertracker/dao/dto/ProductCreateDTO.java new file mode 100644 index 0000000..34b6aac --- /dev/null +++ b/src/main/java/com/chlorocode/tendertracker/dao/dto/ProductCreateDTO.java @@ -0,0 +1,63 @@ +package com.chlorocode.tendertracker.dao.dto; + +import org.hibernate.validator.constraints.NotBlank; + +import javax.validation.Valid; + +/** + * Data transfer object for product creation. + */ +public class ProductCreateDTO { + + @NotBlank(message = "Title is required") + private String title; + + @Valid + private double price; + + private String description; + + private int type; + + private int category; + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public double getPrice() { + return price; + } + + public void setPrice(double price) { + this.price = price; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public int getType() { + return type; + } + + public void setType(int type) { + this.type = type; + } + + public int getCategory() { + return category; + } + + public void setCategory(int category) { + this.category = category; + } +} diff --git a/src/main/java/com/chlorocode/tendertracker/dao/dto/ProductSearchDTO.java b/src/main/java/com/chlorocode/tendertracker/dao/dto/ProductSearchDTO.java new file mode 100644 index 0000000..06cf426 --- /dev/null +++ b/src/main/java/com/chlorocode/tendertracker/dao/dto/ProductSearchDTO.java @@ -0,0 +1,70 @@ +package com.chlorocode.tendertracker.dao.dto; + +/** + * Data transfer object for product search. + */ +public class ProductSearchDTO { + private String searchText; + private String title; + private String description; + private String companyName; + private String orderBy; + private String orderMode; + private boolean advance; + + public String getSearchText() { + return searchText; + } + + public void setSearchText(String searchText) { + this.searchText = searchText; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getCompanyName() { + return companyName; + } + + public void setCompanyName(String companyName) { + this.companyName = companyName; + } + + public String getOrderBy() { + return orderBy; + } + + public void setOrderBy(String orderBy) { + this.orderBy = orderBy; + } + + public String getOrderMode() { + return orderMode; + } + + public void setOrderMode(String orderMode) { + this.orderMode = orderMode; + } + + public boolean isAdvance() { + return advance; + } + + public void setAdvance(boolean advance) { + this.advance = advance; + } +} diff --git a/src/main/java/com/chlorocode/tendertracker/dao/dto/ProductUpdateDTO.java b/src/main/java/com/chlorocode/tendertracker/dao/dto/ProductUpdateDTO.java new file mode 100644 index 0000000..7e124ff --- /dev/null +++ b/src/main/java/com/chlorocode/tendertracker/dao/dto/ProductUpdateDTO.java @@ -0,0 +1,113 @@ +package com.chlorocode.tendertracker.dao.dto; + +import org.hibernate.validator.constraints.NotBlank; + +import javax.validation.Valid; + +/** + * Data transfer object for product update. + */ +public class ProductUpdateDTO { + private int productCode; + + @NotBlank(message = "Title is required") + private String title; + + @Valid + private double price; + + private String description; + + private int type; + + private int category; + + private String response; + + public String getResponse() { + return response; + } + + public void setResponse(String response) { + this.response = response; + } + + private int companyId; + + private String CategoryDescription; + + public String getCategoryDescription() { + return CategoryDescription; + } + + public void setCategoryDescription(String categoryDescription) { + CategoryDescription = categoryDescription; + } + + public int getCompanyId() { + return companyId; + } + + public void setCompanyId(int companyId) { + this.companyId = companyId; + } + + + private boolean published; + + public int getProductCode() { + return productCode; + } + + public void setProductCode(int productCode) { + this.productCode = productCode; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public double getPrice() { + return price; + } + + public void setPrice(double price) { + this.price = price; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public int getType() { + return type; + } + + public void setType(int type) { + this.type = type; + } + + public int getCategory() { + return category; + } + + public void setCategory(int category) { + this.category = category; + } + + public boolean isPublished() { + return published; + } + + public void setPublished(boolean published) { + this.published = published; + } +} diff --git a/src/main/java/com/chlorocode/tendertracker/dao/dto/ReportSummaryDTO.java b/src/main/java/com/chlorocode/tendertracker/dao/dto/ReportSummaryDTO.java new file mode 100644 index 0000000..ee6083b --- /dev/null +++ b/src/main/java/com/chlorocode/tendertracker/dao/dto/ReportSummaryDTO.java @@ -0,0 +1,32 @@ +package com.chlorocode.tendertracker.dao.dto; + +/** + * Created by fistg on 17-Dec-17. + * Data transfer object for report summary. + */ +public class ReportSummaryDTO { + + private String status; + private String count; + + public ReportSummaryDTO(String status, String count) { + this.status = status; + this.count = count; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getCount() { + return count; + } + + public void setCount(String count) { + this.count = count; + } +} diff --git a/src/main/java/com/chlorocode/tendertracker/dao/dto/TenderClarificationDTO.java b/src/main/java/com/chlorocode/tendertracker/dao/dto/TenderClarificationDTO.java index 406caa5..ccedfb7 100644 --- a/src/main/java/com/chlorocode/tendertracker/dao/dto/TenderClarificationDTO.java +++ b/src/main/java/com/chlorocode/tendertracker/dao/dto/TenderClarificationDTO.java @@ -6,6 +6,7 @@ /** * Created by andy on 8/8/2017. + * Data transfer object for tender clarification. */ public class TenderClarificationDTO { private int id; @@ -24,6 +25,24 @@ public class TenderClarificationDTO { private String submittedByEmail; private String submittedByContactNo; private String tenderType; + private double price; + private String description; + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public double getPrice() { + return price; + } + + public void setPrice(double price) { + this.price = price; + } public String getTenderType() { return tenderType; diff --git a/src/main/java/com/chlorocode/tendertracker/dao/dto/TenderCreateDTO.java b/src/main/java/com/chlorocode/tendertracker/dao/dto/TenderCreateDTO.java index 9a9a75c..a466a13 100644 --- a/src/main/java/com/chlorocode/tendertracker/dao/dto/TenderCreateDTO.java +++ b/src/main/java/com/chlorocode/tendertracker/dao/dto/TenderCreateDTO.java @@ -9,6 +9,9 @@ import java.util.LinkedList; import java.util.List; +/** + * Data transfer object for tender create. + */ public class TenderCreateDTO { private String refNo; @@ -29,6 +32,8 @@ public class TenderCreateDTO { @NotNull(message = "Tender Type is required") private int tenderType; + private String invitedCompany; + @NotNull(message = "EPV is required") private float estimatePurchaseValue; private Date deliveryDate; @@ -109,6 +114,14 @@ public void setTenderType(int tenderType) { this.tenderType = tenderType; } + public String getInvitedCompany() { + return invitedCompany; + } + + public void setInvitedCompany(String invitedCompany) { + this.invitedCompany = invitedCompany; + } + public float getEstimatePurchaseValue() { return estimatePurchaseValue; } diff --git a/src/main/java/com/chlorocode/tendertracker/dao/dto/TenderItemCreateDTO.java b/src/main/java/com/chlorocode/tendertracker/dao/dto/TenderItemCreateDTO.java index cd0cca6..41b6bb2 100644 --- a/src/main/java/com/chlorocode/tendertracker/dao/dto/TenderItemCreateDTO.java +++ b/src/main/java/com/chlorocode/tendertracker/dao/dto/TenderItemCreateDTO.java @@ -4,6 +4,9 @@ import javax.validation.constraints.NotNull; +/** + * Data transfer object for tender item creation. + */ public class TenderItemCreateDTO { @NotNull(message = "UOM is required") diff --git a/src/main/java/com/chlorocode/tendertracker/dao/dto/TenderItemResponseSubmitDTO.java b/src/main/java/com/chlorocode/tendertracker/dao/dto/TenderItemResponseSubmitDTO.java index bd52bf9..4cc9956 100644 --- a/src/main/java/com/chlorocode/tendertracker/dao/dto/TenderItemResponseSubmitDTO.java +++ b/src/main/java/com/chlorocode/tendertracker/dao/dto/TenderItemResponseSubmitDTO.java @@ -2,6 +2,9 @@ import com.chlorocode.tendertracker.dao.entity.TenderItem; +/** + * Data transfer object for tender item response submit. + */ public class TenderItemResponseSubmitDTO { private TenderItem item; diff --git a/src/main/java/com/chlorocode/tendertracker/dao/dto/TenderItemUpdateDTO.java b/src/main/java/com/chlorocode/tendertracker/dao/dto/TenderItemUpdateDTO.java index 73d0122..dcb03ae 100644 --- a/src/main/java/com/chlorocode/tendertracker/dao/dto/TenderItemUpdateDTO.java +++ b/src/main/java/com/chlorocode/tendertracker/dao/dto/TenderItemUpdateDTO.java @@ -4,6 +4,9 @@ import javax.validation.constraints.NotNull; +/** + * Data transfer object for tender item update. + */ public class TenderItemUpdateDTO { private int id; diff --git a/src/main/java/com/chlorocode/tendertracker/dao/dto/TenderResponseSubmitDTO.java b/src/main/java/com/chlorocode/tendertracker/dao/dto/TenderResponseSubmitDTO.java index 4fa897a..f6a55f5 100644 --- a/src/main/java/com/chlorocode/tendertracker/dao/dto/TenderResponseSubmitDTO.java +++ b/src/main/java/com/chlorocode/tendertracker/dao/dto/TenderResponseSubmitDTO.java @@ -5,6 +5,9 @@ import java.util.LinkedList; import java.util.List; +/** + * Data transfer object for tender response submit. + */ public class TenderResponseSubmitDTO { private int tenderId; private List attachments; diff --git a/src/main/java/com/chlorocode/tendertracker/dao/dto/TenderSearchDTO.java b/src/main/java/com/chlorocode/tendertracker/dao/dto/TenderSearchDTO.java index 612a36e..3b68e98 100644 --- a/src/main/java/com/chlorocode/tendertracker/dao/dto/TenderSearchDTO.java +++ b/src/main/java/com/chlorocode/tendertracker/dao/dto/TenderSearchDTO.java @@ -1,5 +1,8 @@ package com.chlorocode.tendertracker.dao.dto; +/** + * Data transfer object for tender search. + */ public class TenderSearchDTO { private String searchText; @@ -12,6 +15,10 @@ public class TenderSearchDTO { private int status; + private int tenderSource; + + private String etStatus; + private String refNo; private String orderBy; @@ -99,4 +106,20 @@ public String getOrderMode() { public void setOrderMode(String orderMode) { this.orderMode = orderMode; } + + public String getEtStatus() { + return etStatus; + } + + public void setEtStatus(String etStatus) { + this.etStatus = etStatus; + } + + public int getTenderSource() { + return tenderSource; + } + + public void setTenderSource(int tenderSource) { + this.tenderSource = tenderSource; + } } diff --git a/src/main/java/com/chlorocode/tendertracker/dao/dto/TenderStatusStatisticDTO.java b/src/main/java/com/chlorocode/tendertracker/dao/dto/TenderStatusStatisticDTO.java index 515a7e8..bc3463e 100644 --- a/src/main/java/com/chlorocode/tendertracker/dao/dto/TenderStatusStatisticDTO.java +++ b/src/main/java/com/chlorocode/tendertracker/dao/dto/TenderStatusStatisticDTO.java @@ -1,5 +1,8 @@ package com.chlorocode.tendertracker.dao.dto; +/** + * Data transfer object for tender status statistic. + */ public class TenderStatusStatisticDTO { private String label; private int value; diff --git a/src/main/java/com/chlorocode/tendertracker/dao/dto/TenderUpdateDTO.java b/src/main/java/com/chlorocode/tendertracker/dao/dto/TenderUpdateDTO.java index 44c6732..7e3c4d7 100644 --- a/src/main/java/com/chlorocode/tendertracker/dao/dto/TenderUpdateDTO.java +++ b/src/main/java/com/chlorocode/tendertracker/dao/dto/TenderUpdateDTO.java @@ -9,6 +9,9 @@ import java.util.LinkedList; import java.util.List; +/** + * Data transfer object for tender update. + */ public class TenderUpdateDTO { private int tenderId; private String refNo; diff --git a/src/main/java/com/chlorocode/tendertracker/dao/dto/UserProfileDTO.java b/src/main/java/com/chlorocode/tendertracker/dao/dto/UserProfileDTO.java index d0262f7..0fd6533 100644 --- a/src/main/java/com/chlorocode/tendertracker/dao/dto/UserProfileDTO.java +++ b/src/main/java/com/chlorocode/tendertracker/dao/dto/UserProfileDTO.java @@ -4,6 +4,7 @@ /** * Created by andy on 10/8/2017. + * Data transfer object for user profile. */ public class UserProfileDTO { diff --git a/src/main/java/com/chlorocode/tendertracker/dao/dto/UserRegistrationDTO.java b/src/main/java/com/chlorocode/tendertracker/dao/dto/UserRegistrationDTO.java index fa1ad5b..391445e 100644 --- a/src/main/java/com/chlorocode/tendertracker/dao/dto/UserRegistrationDTO.java +++ b/src/main/java/com/chlorocode/tendertracker/dao/dto/UserRegistrationDTO.java @@ -6,6 +6,9 @@ import javax.validation.constraints.Pattern; +/** + * Data transfer object for user registration. + */ public class UserRegistrationDTO { @NotBlank(message = "Name is required") diff --git a/src/main/java/com/chlorocode/tendertracker/dao/entity/Bid.java b/src/main/java/com/chlorocode/tendertracker/dao/entity/Bid.java index c879565..73c2a17 100644 --- a/src/main/java/com/chlorocode/tendertracker/dao/entity/Bid.java +++ b/src/main/java/com/chlorocode/tendertracker/dao/entity/Bid.java @@ -1,15 +1,22 @@ package com.chlorocode.tendertracker.dao.entity; +import com.fasterxml.jackson.annotation.JsonView; +import org.springframework.data.jpa.datatables.mapping.DataTablesOutput; + import javax.persistence.*; import java.util.Date; import java.util.LinkedList; import java.util.List; +/** + * Bid entity. + */ @Entity public class Bid { @Id @GeneratedValue(strategy = GenerationType.AUTO) + @JsonView(DataTablesOutput.View.class) private int id; private double totalAmount; @@ -24,6 +31,7 @@ public class Bid { private Date lastUpdatedDate; @ManyToOne + @JsonView(DataTablesOutput.View.class) private Tender tender; @ManyToOne @@ -35,6 +43,9 @@ public class Bid { @OneToMany(mappedBy = "bid", cascade = CascadeType.PERSIST) private List documents; + @OneToMany(mappedBy = "bid", cascade = CascadeType.PERSIST) + private List evaluationResults; + public Bid() { this.bidItems = new LinkedList<>(); this.documents = new LinkedList<>(); diff --git a/src/main/java/com/chlorocode/tendertracker/dao/entity/BidDocument.java b/src/main/java/com/chlorocode/tendertracker/dao/entity/BidDocument.java index 1ebd54c..94392c9 100644 --- a/src/main/java/com/chlorocode/tendertracker/dao/entity/BidDocument.java +++ b/src/main/java/com/chlorocode/tendertracker/dao/entity/BidDocument.java @@ -2,28 +2,18 @@ import javax.persistence.*; +/** + * BidDocument entity. + */ @Entity @Table(name = "bid_document") -public class BidDocument { - @Id - @GeneratedValue(strategy = GenerationType.AUTO) - private int id; +@PrimaryKeyJoinColumn(name = "document_id") +@DiscriminatorValue("3") +public class BidDocument extends Document { @ManyToOne private Bid bid; - @OneToOne(cascade = CascadeType.ALL) - @JoinColumn(name="document_id", unique= true, nullable=false) - private Document document; - - public int getId() { - return id; - } - - public void setId(int id) { - this.id = id; - } - public Bid getBid() { return bid; } @@ -32,11 +22,4 @@ public void setBid(Bid bid) { this.bid = bid; } - public Document getDocument() { - return document; - } - - public void setDocument(Document document) { - this.document = document; - } } diff --git a/src/main/java/com/chlorocode/tendertracker/dao/entity/BidItem.java b/src/main/java/com/chlorocode/tendertracker/dao/entity/BidItem.java index 3105430..8020e7d 100644 --- a/src/main/java/com/chlorocode/tendertracker/dao/entity/BidItem.java +++ b/src/main/java/com/chlorocode/tendertracker/dao/entity/BidItem.java @@ -3,6 +3,9 @@ import javax.persistence.*; import java.util.Date; +/** + * BidItem entity. + */ @Entity @Table(name = "bid_item") public class BidItem { diff --git a/src/main/java/com/chlorocode/tendertracker/dao/entity/Clarification.java b/src/main/java/com/chlorocode/tendertracker/dao/entity/Clarification.java index 0ce277d..db637f2 100644 --- a/src/main/java/com/chlorocode/tendertracker/dao/entity/Clarification.java +++ b/src/main/java/com/chlorocode/tendertracker/dao/entity/Clarification.java @@ -8,6 +8,7 @@ /** * Created by andy on 8/8/2017. + * Clarification entity. */ @Entity @Table(name = "clarification") diff --git a/src/main/java/com/chlorocode/tendertracker/dao/entity/CodeValue.java b/src/main/java/com/chlorocode/tendertracker/dao/entity/CodeValue.java index 4c7bccb..a99e46b 100644 --- a/src/main/java/com/chlorocode/tendertracker/dao/entity/CodeValue.java +++ b/src/main/java/com/chlorocode/tendertracker/dao/entity/CodeValue.java @@ -2,6 +2,9 @@ import javax.persistence.*; +/** + * CodeValue entity. + */ @Entity @Table(name = "code_value") public class CodeValue { diff --git a/src/main/java/com/chlorocode/tendertracker/dao/entity/Company.java b/src/main/java/com/chlorocode/tendertracker/dao/entity/Company.java index 01947ef..e4c439b 100644 --- a/src/main/java/com/chlorocode/tendertracker/dao/entity/Company.java +++ b/src/main/java/com/chlorocode/tendertracker/dao/entity/Company.java @@ -6,6 +6,7 @@ import javax.persistence.*; import java.util.Date; +import java.util.LinkedList; import java.util.List; @Entity @@ -32,17 +33,34 @@ public class Company { private String state; private String province; + @Column(name = "is_active") + @JsonView(DataTablesOutput.View.class) + private boolean isActive; + + public boolean isActive() { + return isActive; + } + + public void setActive(boolean active) { + isActive = active; + } + @ManyToOne @JoinColumn(name = "country") private Country country; private int areaOfBusiness; + + @JsonView(DataTablesOutput.View.class) private int status; private int createdBy; @Column(name = "principle_business_activity") private String princpleBusinessActivity; + @ManyToMany(mappedBy = "invitedCompanies") + private List invitedTenders; + public String getPrincpleBusinessActivity() { return princpleBusinessActivity; } @@ -52,7 +70,7 @@ public void setPrincpleBusinessActivity(String princpleBusinessActivity) { } public Company(){ - + invitedTenders = new LinkedList<>(); } public Company(String name, String uen, String gstRegNo, int type, String address1, String address2, String postalCode, String city, String state, String province, Country country, int areaOfBusiness, int createdBy, @@ -73,6 +91,8 @@ public Company(String name, String uen, String gstRegNo, int type, String addres this.createdDate = createdDate; this.lastUpdatedBy = lastUpdatedBy; this.lastUpdatedDate = lastUpdatedDate; + + invitedTenders = new LinkedList<>(); } @JsonView(DataTablesOutput.View.class) @@ -255,4 +275,8 @@ public boolean isPostalCodeValid() { } return true; } + + public List getInvitedTenders() { + return invitedTenders; + } } diff --git a/src/main/java/com/chlorocode/tendertracker/dao/entity/Company_.java b/src/main/java/com/chlorocode/tendertracker/dao/entity/Company_.java index c708ab7..4520bf4 100644 --- a/src/main/java/com/chlorocode/tendertracker/dao/entity/Company_.java +++ b/src/main/java/com/chlorocode/tendertracker/dao/entity/Company_.java @@ -4,8 +4,12 @@ import javax.persistence.metamodel.SingularAttribute; import javax.persistence.metamodel.StaticMetamodel; +/** + * Company_ for creating specification criteria for query. + */ @Generated(value = "org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor") @StaticMetamodel(Company.class) public abstract class Company_ { + public static volatile SingularAttribute id; public static volatile SingularAttribute name; } diff --git a/src/main/java/com/chlorocode/tendertracker/dao/entity/Corrigendum.java b/src/main/java/com/chlorocode/tendertracker/dao/entity/Corrigendum.java index 9a87cfe..5af0780 100644 --- a/src/main/java/com/chlorocode/tendertracker/dao/entity/Corrigendum.java +++ b/src/main/java/com/chlorocode/tendertracker/dao/entity/Corrigendum.java @@ -5,6 +5,9 @@ import java.util.LinkedList; import java.util.List; +/** + * Corrigendum entity. + */ @Entity public class Corrigendum { diff --git a/src/main/java/com/chlorocode/tendertracker/dao/entity/CorrigendumDocument.java b/src/main/java/com/chlorocode/tendertracker/dao/entity/CorrigendumDocument.java index 9a8c2f4..b3dff51 100644 --- a/src/main/java/com/chlorocode/tendertracker/dao/entity/CorrigendumDocument.java +++ b/src/main/java/com/chlorocode/tendertracker/dao/entity/CorrigendumDocument.java @@ -2,28 +2,18 @@ import javax.persistence.*; +/** + * CorrigendumDocument entity. + */ @Entity -public class CorrigendumDocument { - - @Id - @GeneratedValue(strategy = GenerationType.AUTO) - private int id; +@Table(name = "corrigendum_document") +@PrimaryKeyJoinColumn(name = "document_id") +@DiscriminatorValue("2") +public class CorrigendumDocument extends Document { @ManyToOne private Corrigendum corrigendum; - @OneToOne(cascade = CascadeType.ALL) - @JoinColumn(name="document_id", unique= true, nullable=false) - private Document document; - - public int getId() { - return id; - } - - public void setId(int id) { - this.id = id; - } - public Corrigendum getCorrigendum() { return corrigendum; } @@ -32,11 +22,4 @@ public void setCorrigendum(Corrigendum corrigendum) { this.corrigendum = corrigendum; } - public Document getDocument() { - return document; - } - - public void setDocument(Document document) { - this.document = document; - } } diff --git a/src/main/java/com/chlorocode/tendertracker/dao/entity/Country.java b/src/main/java/com/chlorocode/tendertracker/dao/entity/Country.java index 1db62fc..6504c23 100644 --- a/src/main/java/com/chlorocode/tendertracker/dao/entity/Country.java +++ b/src/main/java/com/chlorocode/tendertracker/dao/entity/Country.java @@ -4,6 +4,9 @@ import javax.persistence.Entity; import javax.persistence.Id; +/** + * Country entity. + */ @Entity public class Country { diff --git a/src/main/java/com/chlorocode/tendertracker/dao/entity/CurrentUser.java b/src/main/java/com/chlorocode/tendertracker/dao/entity/CurrentUser.java index f9dfe97..163e969 100644 --- a/src/main/java/com/chlorocode/tendertracker/dao/entity/CurrentUser.java +++ b/src/main/java/com/chlorocode/tendertracker/dao/entity/CurrentUser.java @@ -4,6 +4,9 @@ import java.util.List; +/** + * This class is used for login authentication by spring framework. + */ public class CurrentUser extends org.springframework.security.core.userdetails.User { private User user; diff --git a/src/main/java/com/chlorocode/tendertracker/dao/entity/Document.java b/src/main/java/com/chlorocode/tendertracker/dao/entity/Document.java index 09febf9..445e811 100644 --- a/src/main/java/com/chlorocode/tendertracker/dao/entity/Document.java +++ b/src/main/java/com/chlorocode/tendertracker/dao/entity/Document.java @@ -3,9 +3,13 @@ import javax.persistence.*; import java.util.Date; +/** + * Base class for every type of Document. + */ @Entity -@Table(name = "document") -public class Document { +@Inheritance(strategy = InheritanceType.JOINED) +@DiscriminatorColumn(name="type") +public abstract class Document { @Id @GeneratedValue(strategy = GenerationType.AUTO) @@ -13,7 +17,6 @@ public class Document { private String name; private String location; - private int type; private int createdBy; @Temporal(TemporalType.TIMESTAMP) @@ -48,14 +51,6 @@ public void setLocation(String location) { this.location = location; } - public int getType() { - return type; - } - - public void setType(int type) { - this.type = type; - } - public int getCreatedBy() { return createdBy; } diff --git a/src/main/java/com/chlorocode/tendertracker/dao/entity/EvaluationCriteria.java b/src/main/java/com/chlorocode/tendertracker/dao/entity/EvaluationCriteria.java index 8cf5e18..33f1114 100644 --- a/src/main/java/com/chlorocode/tendertracker/dao/entity/EvaluationCriteria.java +++ b/src/main/java/com/chlorocode/tendertracker/dao/entity/EvaluationCriteria.java @@ -5,9 +5,11 @@ import javax.persistence.*; import java.util.Date; +import java.util.List; /** * Created by andy on 1/8/2017. + * EvaluationCriteria entity. */ @Entity @Table(name = "evaluation_criteria") @@ -37,6 +39,9 @@ public class EvaluationCriteria { @Column(name = "last_updated_date") private Date lastUpdatedDate; + @OneToMany(mappedBy = "criteria") + private List results; + public int getId() { return id; } diff --git a/src/main/java/com/chlorocode/tendertracker/dao/entity/EvaluationResult.java b/src/main/java/com/chlorocode/tendertracker/dao/entity/EvaluationResult.java new file mode 100644 index 0000000..17c9dd6 --- /dev/null +++ b/src/main/java/com/chlorocode/tendertracker/dao/entity/EvaluationResult.java @@ -0,0 +1,113 @@ +package com.chlorocode.tendertracker.dao.entity; + +import javax.persistence.*; +import java.util.Date; + +/** + * EvaluationResult entity. + */ +@Entity +@Table(name = "evaluation_result") +public class EvaluationResult { + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + private int id; + + @ManyToOne + private Bid bid; + + @ManyToOne + @JoinColumn(name = "user_id") + private User evaluator; + + @ManyToOne + private EvaluationCriteria criteria; + + private int result; + + @Column(name = "created_by") + private int createdBy; + + @Temporal(TemporalType.TIMESTAMP) + @Column(name = "created_date") + private Date createdDate; + + @Column(name = "last_updated_by") + private int lastUpdatedBy; + + @Temporal(TemporalType.TIMESTAMP) + @Column(name = "last_updated_date") + private Date lastUpdatedDate; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public Bid getBid() { + return bid; + } + + public void setBid(Bid bid) { + this.bid = bid; + } + + public User getEvaluator() { + return evaluator; + } + + public void setEvaluator(User evaluator) { + this.evaluator = evaluator; + } + + public EvaluationCriteria getCriteria() { + return criteria; + } + + public void setCriteria(EvaluationCriteria criteria) { + this.criteria = criteria; + } + + public int getResult() { + return result; + } + + public void setResult(int result) { + this.result = result; + } + + public int getCreatedBy() { + return createdBy; + } + + public void setCreatedBy(int createdBy) { + this.createdBy = createdBy; + } + + public Date getCreatedDate() { + return createdDate; + } + + public void setCreatedDate(Date createdDate) { + this.createdDate = createdDate; + } + + public int getLastUpdatedBy() { + return lastUpdatedBy; + } + + public void setLastUpdatedBy(int lastUpdatedBy) { + this.lastUpdatedBy = lastUpdatedBy; + } + + public Date getLastUpdatedDate() { + return lastUpdatedDate; + } + + public void setLastUpdatedDate(Date lastUpdatedDate) { + this.lastUpdatedDate = lastUpdatedDate; + } +} diff --git a/src/main/java/com/chlorocode/tendertracker/dao/entity/ExternalTender.java b/src/main/java/com/chlorocode/tendertracker/dao/entity/ExternalTender.java new file mode 100644 index 0000000..7cf37bf --- /dev/null +++ b/src/main/java/com/chlorocode/tendertracker/dao/entity/ExternalTender.java @@ -0,0 +1,161 @@ +package com.chlorocode.tendertracker.dao.entity; + +import com.fasterxml.jackson.annotation.JsonView; +import org.springframework.data.jpa.datatables.mapping.DataTablesOutput; + +import javax.persistence.*; +import java.util.Date; + +/** + * Created by Kyaw Min Thu on 3/7/2017. + * ExternalTender entity. + */ +@Entity +@Table(name = "external_tender") +public class ExternalTender { + @Id + @JsonView(DataTablesOutput.View.class) + @GeneratedValue(strategy = GenerationType.AUTO) + private long id; + + @Column(name = "reference_no") + @JsonView(DataTablesOutput.View.class) + private String referenceNo; + + @JsonView(DataTablesOutput.View.class) + private String title; + + @JsonView(DataTablesOutput.View.class) + @Column(name = "company_name") + private String companyName; + + @JsonView(DataTablesOutput.View.class) + @Column(name = "published_date") + private Date publishedDate; + + @JsonView(DataTablesOutput.View.class) + @Column(name = "closing_date") + private Date closingDate; + + @JsonView(DataTablesOutput.View.class) + private String status; + + @JsonView(DataTablesOutput.View.class) + @Column(name = "tender_url") + private String tenderURL; + + @JsonView(DataTablesOutput.View.class) + @Column(name = "tender_source") + private String tenderSource; + + @Temporal(TemporalType.TIMESTAMP) + @Column(name = "created_date") + private Date createdDate; + + @Temporal(TemporalType.TIMESTAMP) + @Column(name = "last_updated_date") + private Date lastUpdatedDate; + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public String getReferenceNo() { + return referenceNo; + } + + public void setReferenceNo(String referenceNo) { + this.referenceNo = referenceNo; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getCompanyName() { + return companyName; + } + + public void setCompanyName(String companyName) { + this.companyName = companyName; + } + + public Date getPublishedDate() { + return publishedDate; + } + + public void setPublishedDate(Date publishedDate) { + this.publishedDate = publishedDate; + } + + public Date getClosingDate() { + return closingDate; + } + + public void setClosingDate(Date closingDate) { + this.closingDate = closingDate; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getTenderURL() { + return tenderURL; + } + + public void setTenderURL(String tenderURL) { + this.tenderURL = tenderURL; + } + + public String getTenderSource() { + return tenderSource; + } + + public void setTenderSource(String tenderSource) { + this.tenderSource = tenderSource; + } + + public Date getCreatedDate() { + return createdDate; + } + + public void setCreatedDate(Date createdDate) { + this.createdDate = createdDate; + } + + public Date getLastUpdatedDate() { + return lastUpdatedDate; + } + + public void setLastUpdatedDate(Date lastUpdatedDate) { + this.lastUpdatedDate = lastUpdatedDate; + } + + @Override + public String toString() { + return "ExternalTender{" + + "id=" + id + + ", referenceNo='" + referenceNo + '\'' + + ", title='" + title + '\'' + + ", companyName='" + companyName + '\'' + + ", publishedDate='" + publishedDate + '\'' + + ", closingDate='" + closingDate + '\'' + + ", status='" + status + '\'' + + ", tenderURL='" + tenderURL + '\'' + + ", tenderSource='" + tenderSource + '\'' + + '}'; + } +} diff --git a/src/main/java/com/chlorocode/tendertracker/dao/entity/ExternalTender_.java b/src/main/java/com/chlorocode/tendertracker/dao/entity/ExternalTender_.java new file mode 100644 index 0000000..ef66248 --- /dev/null +++ b/src/main/java/com/chlorocode/tendertracker/dao/entity/ExternalTender_.java @@ -0,0 +1,22 @@ +package com.chlorocode.tendertracker.dao.entity; + +import javax.annotation.Generated; +import javax.persistence.metamodel.SingularAttribute; +import javax.persistence.metamodel.StaticMetamodel; +import java.util.Date; + +/** + * This class is used to create specification cirteria for query. + */ +@Generated(value = "org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor") +@StaticMetamodel(ExternalTender.class) +public abstract class ExternalTender_ { + public static volatile SingularAttribute title; + public static volatile SingularAttribute referenceNo; + public static volatile SingularAttribute status; + public static volatile SingularAttribute tenderSource; + public static volatile SingularAttribute companyName; + public static volatile SingularAttribute description; +// public static volatile SingularAttribute tenderCategory; + public static volatile SingularAttribute publishedDate; +} diff --git a/src/main/java/com/chlorocode/tendertracker/dao/entity/Milestone.java b/src/main/java/com/chlorocode/tendertracker/dao/entity/Milestone.java new file mode 100644 index 0000000..4cc228e --- /dev/null +++ b/src/main/java/com/chlorocode/tendertracker/dao/entity/Milestone.java @@ -0,0 +1,144 @@ +package com.chlorocode.tendertracker.dao.entity; + +import com.fasterxml.jackson.annotation.JsonView; +import org.springframework.data.jpa.datatables.mapping.DataTablesOutput; + +import javax.persistence.*; +import java.util.Date; + +/** + * Created by Kyaw Min Thu on 6/1/2018. + * Milestone entity. + */ +@Entity +@Table(name = "milestone") +public class Milestone { + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + @JsonView(DataTablesOutput.View.class) + private int id; + + @ManyToOne + private Tender tender; + + private String description; + + @Temporal(TemporalType.TIMESTAMP) + @Column(name = "due_date") + private Date dueDate; + + private int status; + + @Column(name = "notify_status") + private int notifyStatus; + + @Column(name = "created_by") + private int createdBy; + + @Temporal(TemporalType.TIMESTAMP) + @Column(name = "created_date") + private Date createdDate; + + @Column(name = "last_updated_by") + private int lastUpdatedBy; + + @Temporal(TemporalType.TIMESTAMP) + @Column(name = "last_updated_date") + private Date lastUpdatedDate; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public Tender getTender() { + return tender; + } + + public void setTender(Tender tender) { + this.tender = tender; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public Date getDueDate() { + return dueDate; + } + + public void setDueDate(Date dueDate) { + this.dueDate = dueDate; + } + + public int getStatus() { + return status; + } + + public void setStatus(int status) { + this.status = status; + } + + public int getNotifyStatus() { + return notifyStatus; + } + + public void setNotifyStatus(int notifyStatus) { + this.notifyStatus = notifyStatus; + } + + public int getCreatedBy() { + return createdBy; + } + + public void setCreatedBy(int createdBy) { + this.createdBy = createdBy; + } + + public Date getCreatedDate() { + return createdDate; + } + + public void setCreatedDate(Date createdDate) { + this.createdDate = createdDate; + } + + public int getLastUpdatedBy() { + return lastUpdatedBy; + } + + public void setLastUpdatedBy(int lastUpdatedBy) { + this.lastUpdatedBy = lastUpdatedBy; + } + + public Date getLastUpdatedDate() { + return lastUpdatedDate; + } + + public void setLastUpdatedDate(Date lastUpdatedDate) { + this.lastUpdatedDate = lastUpdatedDate; + } + + @Override + public String toString() { + return "Milestone{" + + "id=" + id + + ", tender=" + tender + + ", description='" + description + '\'' + + ", dueDate=" + dueDate + + ", status=" + status + + ", notifyStatus=" + notifyStatus + + ", createdBy=" + createdBy + + ", createdDate=" + createdDate + + ", lastUpdatedBy=" + lastUpdatedBy + + ", lastUpdatedDate=" + lastUpdatedDate + + '}'; + } +} diff --git a/src/main/java/com/chlorocode/tendertracker/dao/entity/Product.java b/src/main/java/com/chlorocode/tendertracker/dao/entity/Product.java new file mode 100644 index 0000000..9d52910 --- /dev/null +++ b/src/main/java/com/chlorocode/tendertracker/dao/entity/Product.java @@ -0,0 +1,164 @@ +package com.chlorocode.tendertracker.dao.entity; + +import com.fasterxml.jackson.annotation.JsonView; +import org.springframework.data.jpa.datatables.mapping.DataTablesOutput; + +import javax.persistence.*; +import java.util.Date; +import java.util.List; + +/** + * Product entity. + */ +@Entity +public class Product { + + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + @JsonView(DataTablesOutput.View.class) + private int productCode; + + @JsonView(DataTablesOutput.View.class) + private String title; + + @JsonView(DataTablesOutput.View.class) + private double price; + + @JsonView(DataTablesOutput.View.class) + private String description; + + @JsonView(DataTablesOutput.View.class) + private boolean publish; + + private int type; + private int category; + private int status; + + public int getStatus() { + return status; + } + + public void setStatus(int status) { + this.status = status; + } + + @JsonView(DataTablesOutput.View.class) + @ManyToOne + private Company company; + + @OneToMany(mappedBy = "product") + private List clarifications; + + private int createdBy; + + @Temporal(TemporalType.TIMESTAMP) + private Date createdDate; + + private int lastUpdatedBy; + + @Temporal(TemporalType.TIMESTAMP) + private Date lastUpdatedDate; + + public int getProductCode() { + return productCode; + } + + public void setProductCode(int productCode) { + this.productCode = productCode; + } + + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + + public double getPrice() { + return price; + } + + public void setPrice(double price) { + this.price = price; + } + + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public Company getCompany() { + return company; + } + + public void setCompany(Company company) { + this.company = company; + } + + public boolean isPublish() { + return publish; + } + + public void setPublish(boolean publish) { + this.publish = publish; + } + + public int getType() { + return type; + } + + public void setType(int type) { + this.type = type; + } + + public int getCategory() { + return category; + } + + public void setCategory(int category) { + this.category = category; + } + + public int getCreatedBy() { + return createdBy; + } + + public void setCreatedBy(int createdBy) { + this.createdBy = createdBy; + } + + public Date getCreatedDate() { + return createdDate; + } + + public void setCreatedDate(Date createdDate) { + this.createdDate = createdDate; + } + + public int getLastUpdatedBy() { + return lastUpdatedBy; + } + + public void setLastUpdatedBy(int lastUpdatedBy) { + this.lastUpdatedBy = lastUpdatedBy; + } + + public Date getLastUpdatedDate() { + return lastUpdatedDate; + } + + public void setLastUpdatedDate(Date lastUpdatedDate) { + this.lastUpdatedDate = lastUpdatedDate; + } + + public List getClarifications() { + return clarifications; + } +} diff --git a/src/main/java/com/chlorocode/tendertracker/dao/entity/ProductClarification.java b/src/main/java/com/chlorocode/tendertracker/dao/entity/ProductClarification.java new file mode 100644 index 0000000..ab0ce47 --- /dev/null +++ b/src/main/java/com/chlorocode/tendertracker/dao/entity/ProductClarification.java @@ -0,0 +1,133 @@ +package com.chlorocode.tendertracker.dao.entity; + +import com.fasterxml.jackson.annotation.JsonView; +import org.springframework.data.jpa.datatables.mapping.DataTablesOutput; + +import javax.persistence.*; +import java.util.Date; + +/** + * Created by andy on 18/1/2018. + * ProductClarification entity. + */ +@Entity +public class ProductClarification { + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + @JsonView(DataTablesOutput.View.class) + private int id; + + @JsonView(DataTablesOutput.View.class) + @ManyToOne + private Company company; + + @JsonView(DataTablesOutput.View.class) + @ManyToOne + @JoinColumn(name = "product_code") + private Product product; + + @JsonView(DataTablesOutput.View.class) + private String description; + + private int status; + + @JsonView(DataTablesOutput.View.class) + private String response; + + @Column(name = "created_by") + private int createdBy; + + @JsonView(DataTablesOutput.View.class) + @Temporal(TemporalType.TIMESTAMP) + @Column(name = "created_date") + private Date createdDate; + + @Column(name = "last_updated_by") + private int lastUpdatedBy; + + @JsonView(DataTablesOutput.View.class) + @Temporal(TemporalType.TIMESTAMP) + @Column(name = "last_updated_date") + private Date lastUpdatedDate; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public Company getCompany() { + return company; + } + + public void setCompany(Company company) { + this.company = company; + } + + public Product getProduct() { + return product; + } + + public void setProduct(Product product) { + this.product = product; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public int getStatus() { + return status; + } + + public void setStatus(int status) { + this.status = status; + } + + public String getResponse() { + return response; + } + + public void setResponse(String response) { + this.response = response; + } + + public int getCreatedBy() { + return createdBy; + } + + public void setCreatedBy(int createdBy) { + this.createdBy = createdBy; + } + + public Date getCreatedDate() { + return createdDate; + } + + public void setCreatedDate(Date createdDate) { + this.createdDate = createdDate; + } + + public int getLastUpdatedBy() { + return lastUpdatedBy; + } + + public void setLastUpdatedBy(int lastUpdatedBy) { + this.lastUpdatedBy = lastUpdatedBy; + } + + public Date getLastUpdatedDate() { + return lastUpdatedDate; + } + + public void setLastUpdatedDate(Date lastUpdatedDate) { + this.lastUpdatedDate = lastUpdatedDate; + } +} + diff --git a/src/main/java/com/chlorocode/tendertracker/dao/entity/Product_.java b/src/main/java/com/chlorocode/tendertracker/dao/entity/Product_.java new file mode 100644 index 0000000..008e541 --- /dev/null +++ b/src/main/java/com/chlorocode/tendertracker/dao/entity/Product_.java @@ -0,0 +1,17 @@ +package com.chlorocode.tendertracker.dao.entity; + +import javax.annotation.Generated; +import javax.persistence.metamodel.SingularAttribute; +import javax.persistence.metamodel.StaticMetamodel; + +/** + * This class is used to create specification cirteria for query. + */ +@Generated(value = "org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor") +@StaticMetamodel(Product.class) +public abstract class Product_ { + public static volatile SingularAttribute title; + public static volatile SingularAttribute description; + public static volatile SingularAttribute company; + public static volatile SingularAttribute publish; +} diff --git a/src/main/java/com/chlorocode/tendertracker/dao/entity/Role.java b/src/main/java/com/chlorocode/tendertracker/dao/entity/Role.java index 784a4d4..1b4eb53 100644 --- a/src/main/java/com/chlorocode/tendertracker/dao/entity/Role.java +++ b/src/main/java/com/chlorocode/tendertracker/dao/entity/Role.java @@ -5,6 +5,9 @@ import javax.persistence.GenerationType; import javax.persistence.Id; +/** + * Role entity. + */ @Entity public class Role { diff --git a/src/main/java/com/chlorocode/tendertracker/dao/entity/RoleUser.java b/src/main/java/com/chlorocode/tendertracker/dao/entity/RoleUser.java index 61a0951..1174209 100644 --- a/src/main/java/com/chlorocode/tendertracker/dao/entity/RoleUser.java +++ b/src/main/java/com/chlorocode/tendertracker/dao/entity/RoleUser.java @@ -5,6 +5,7 @@ /** * Created by andy on 19/7/2017. + * RoleUser entity. */ @Entity @Table(name = "user_role") diff --git a/src/main/java/com/chlorocode/tendertracker/dao/entity/Tender.java b/src/main/java/com/chlorocode/tendertracker/dao/entity/Tender.java index ddfa841..ce93119 100644 --- a/src/main/java/com/chlorocode/tendertracker/dao/entity/Tender.java +++ b/src/main/java/com/chlorocode/tendertracker/dao/entity/Tender.java @@ -8,6 +8,9 @@ import java.util.LinkedList; import java.util.List; +/** + * Tender entity. + */ @Entity public class Tender { @@ -36,6 +39,9 @@ public class Tender { @ManyToOne private TenderCategory tenderCategory; + @OneToOne(mappedBy = "tender") + private TenderAward tenderAward; + private String description; private int tenderType; private float estimatePurchaseValue; @@ -46,6 +52,7 @@ public class Tender { private String contactPersonName; private String contactPersonEmail; private String contactPersonPhone; + @JsonView(DataTablesOutput.View.class) private int status; private int createdBy; @@ -58,6 +65,7 @@ public class Tender { private Date lastUpdatedDate; @OneToMany(mappedBy = "tender", cascade = CascadeType.PERSIST) + @OrderBy("sort") private List items; @OneToMany(mappedBy = "tender", cascade = CascadeType.PERSIST) @@ -72,11 +80,23 @@ public class Tender { @OneToMany(mappedBy = "tender", cascade = CascadeType.PERSIST) private List corrigendums; + @ManyToMany(cascade = { CascadeType.PERSIST, CascadeType.MERGE }) + @JoinTable(name = "tender_invite", + joinColumns = @JoinColumn(name = "tender_id"), + inverseJoinColumns = @JoinColumn(name = "company_id") + ) + private List invitedCompanies; + + @OneToMany(mappedBy = "tender", cascade = CascadeType.PERSIST) + private List tenderVisits; + public Tender() { items = new LinkedList<>(); documents = new LinkedList<>(); tenderBookmarks = new LinkedList<>(); corrigendums = new LinkedList<>(); + invitedCompanies = new LinkedList<>(); + tenderVisits = new LinkedList<>(); } public int getId() { @@ -289,4 +309,29 @@ public List getTenderBookmarks() { public List getCorrigendums() { return corrigendums; } + + public List getInvitedCompanies() { + return invitedCompanies; + } + + public void addInvitedCompany(Company company) { + invitedCompanies.add(company); + } + + public List getTenderVisits() { + return tenderVisits; + } + + public void addTenderVisit(TenderVisit visit) { + tenderVisits.add(visit); + visit.setTender(this); + } + + public TenderAward getTenderAward() { + return tenderAward; + } + + public void setTenderAward(TenderAward tenderAward) { + this.tenderAward = tenderAward; + } } diff --git a/src/main/java/com/chlorocode/tendertracker/dao/entity/TenderAppeal.java b/src/main/java/com/chlorocode/tendertracker/dao/entity/TenderAppeal.java new file mode 100644 index 0000000..8984c9c --- /dev/null +++ b/src/main/java/com/chlorocode/tendertracker/dao/entity/TenderAppeal.java @@ -0,0 +1,123 @@ +package com.chlorocode.tendertracker.dao.entity; + +import com.fasterxml.jackson.annotation.JsonView; +import org.springframework.data.jpa.datatables.mapping.DataTablesOutput; + +import javax.persistence.*; +import java.util.Date; + +/** + * Created by andy on 14/1/2018. + * TenderAppeal entity. + */ +@Entity +@Table(name = "tender_appeal") +public class TenderAppeal { + + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + @JsonView(DataTablesOutput.View.class) + private int id; + + @JsonView(DataTablesOutput.View.class) + @ManyToOne + private Company company; + + @JsonView(DataTablesOutput.View.class) + @ManyToOne + private Tender tender; + + @Column(name = "created_by") + private int createdBy; + + @JsonView(DataTablesOutput.View.class) + @Temporal(TemporalType.TIMESTAMP) + @Column(name = "created_date") + private Date createdDate; + + @Column(name = "last_updated_by") + private int lastUpdatedBy; + + @JsonView(DataTablesOutput.View.class) + @Temporal(TemporalType.TIMESTAMP) + @Column(name = "last_updated_date") + private Date lastUpdatedDate; + + @JsonView(DataTablesOutput.View.class) + private String reasons; + + @JsonView(DataTablesOutput.View.class) + private int status; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public Company getCompany() { + return company; + } + + public void setCompany(Company company) { + this.company = company; + } + + public Tender getTender() { + return tender; + } + + public void setTender(Tender tender) { + this.tender = tender; + } + + public int getCreatedBy() { + return createdBy; + } + + public void setCreatedBy(int createdBy) { + this.createdBy = createdBy; + } + + public Date getCreatedDate() { + return createdDate; + } + + public void setCreatedDate(Date createdDate) { + this.createdDate = createdDate; + } + + public int getLastUpdatedBy() { + return lastUpdatedBy; + } + + public void setLastUpdatedBy(int lastUpdatedBy) { + this.lastUpdatedBy = lastUpdatedBy; + } + + public Date getLastUpdatedDate() { + return lastUpdatedDate; + } + + public void setLastUpdatedDate(Date lastUpdatedDate) { + this.lastUpdatedDate = lastUpdatedDate; + } + + public String getReasons() { + return reasons; + } + + public void setReasons(String reasons) { + this.reasons = reasons; + } + + public int getStatus() { + return status; + } + + public void setStatus(int status) { + this.status = status; + } +} diff --git a/src/main/java/com/chlorocode/tendertracker/dao/entity/TenderAward.java b/src/main/java/com/chlorocode/tendertracker/dao/entity/TenderAward.java new file mode 100644 index 0000000..4bd1bd2 --- /dev/null +++ b/src/main/java/com/chlorocode/tendertracker/dao/entity/TenderAward.java @@ -0,0 +1,102 @@ +package com.chlorocode.tendertracker.dao.entity; + +import javax.persistence.*; +import java.util.Date; + +/** + * TenderAward entity. + */ +@Entity +@Table(name = "tender_award") +public class TenderAward { + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + private int id; + + @OneToOne + private Bid bid; + + @OneToOne + private Tender tender; + + @OneToOne + private Company company; + + @Column(name = "created_by") + private int createdBy; + + @Temporal(TemporalType.TIMESTAMP) + @Column(name = "created_date") + private Date createdDate; + + @Column(name = "last_updated_by") + private int lastUpdatedBy; + + @Temporal(TemporalType.TIMESTAMP) + @Column(name = "last_updated_date") + private Date lastUpdatedDate; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public Bid getBid() { + return bid; + } + + public void setBid(Bid bid) { + this.bid = bid; + } + + public Tender getTender() { + return tender; + } + + public void setTender(Tender tender) { + this.tender = tender; + } + + public Company getCompany() { + return company; + } + + public void setCompany(Company company) { + this.company = company; + } + + public int getCreatedBy() { + return createdBy; + } + + public void setCreatedBy(int createdBy) { + this.createdBy = createdBy; + } + + public Date getCreatedDate() { + return createdDate; + } + + public void setCreatedDate(Date createdDate) { + this.createdDate = createdDate; + } + + public int getLastUpdatedBy() { + return lastUpdatedBy; + } + + public void setLastUpdatedBy(int lastUpdatedBy) { + this.lastUpdatedBy = lastUpdatedBy; + } + + public Date getLastUpdatedDate() { + return lastUpdatedDate; + } + + public void setLastUpdatedDate(Date lastUpdatedDate) { + this.lastUpdatedDate = lastUpdatedDate; + } +} diff --git a/src/main/java/com/chlorocode/tendertracker/dao/entity/TenderBookmark.java b/src/main/java/com/chlorocode/tendertracker/dao/entity/TenderBookmark.java index fcd41af..c30c3cc 100644 --- a/src/main/java/com/chlorocode/tendertracker/dao/entity/TenderBookmark.java +++ b/src/main/java/com/chlorocode/tendertracker/dao/entity/TenderBookmark.java @@ -3,6 +3,9 @@ import javax.persistence.*; import java.util.Date; +/** + * TenderBookmark entity. + */ @Entity @Table(name = "tender_bookmark") public class TenderBookmark { diff --git a/src/main/java/com/chlorocode/tendertracker/dao/entity/TenderCategory.java b/src/main/java/com/chlorocode/tendertracker/dao/entity/TenderCategory.java index b212051..9ab3951 100644 --- a/src/main/java/com/chlorocode/tendertracker/dao/entity/TenderCategory.java +++ b/src/main/java/com/chlorocode/tendertracker/dao/entity/TenderCategory.java @@ -3,6 +3,9 @@ import javax.persistence.*; import java.util.List; +/** + * TenderCategory entity. + */ @Entity @Table(name = "tender_category") public class TenderCategory { diff --git a/src/main/java/com/chlorocode/tendertracker/dao/entity/TenderCategorySubscription.java b/src/main/java/com/chlorocode/tendertracker/dao/entity/TenderCategorySubscription.java index b966fb4..7f5b9ec 100644 --- a/src/main/java/com/chlorocode/tendertracker/dao/entity/TenderCategorySubscription.java +++ b/src/main/java/com/chlorocode/tendertracker/dao/entity/TenderCategorySubscription.java @@ -3,6 +3,9 @@ import javax.persistence.*; import java.util.Date; +/** + * TenderCategorySubscription entity. + */ @Entity @Table(name = "tender_category_subscription") public class TenderCategorySubscription { diff --git a/src/main/java/com/chlorocode/tendertracker/dao/entity/TenderCategory_.java b/src/main/java/com/chlorocode/tendertracker/dao/entity/TenderCategory_.java index c1df6a9..2bb6229 100644 --- a/src/main/java/com/chlorocode/tendertracker/dao/entity/TenderCategory_.java +++ b/src/main/java/com/chlorocode/tendertracker/dao/entity/TenderCategory_.java @@ -4,6 +4,9 @@ import javax.persistence.metamodel.SingularAttribute; import javax.persistence.metamodel.StaticMetamodel; +/** + * This class is used to create specification cirteria for query. + */ @Generated(value = "org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor") @StaticMetamodel(TenderCategory.class) public abstract class TenderCategory_ { diff --git a/src/main/java/com/chlorocode/tendertracker/dao/entity/TenderDocument.java b/src/main/java/com/chlorocode/tendertracker/dao/entity/TenderDocument.java index 286b92d..64a7065 100644 --- a/src/main/java/com/chlorocode/tendertracker/dao/entity/TenderDocument.java +++ b/src/main/java/com/chlorocode/tendertracker/dao/entity/TenderDocument.java @@ -2,29 +2,18 @@ import javax.persistence.*; +/** + * TenderDocument entity. + */ @Entity @Table(name = "tender_document") -public class TenderDocument { - - @Id - @GeneratedValue(strategy = GenerationType.AUTO) - private int id; +@PrimaryKeyJoinColumn(name = "document_id") +@DiscriminatorValue("1") +public class TenderDocument extends Document { @ManyToOne private Tender tender; - @OneToOne(cascade = CascadeType.ALL) - @JoinColumn(name="document_id", unique= true, nullable=false) - private Document document; - - public int getId() { - return id; - } - - public void setId(int id) { - this.id = id; - } - public Tender getTender() { return tender; } @@ -32,12 +21,4 @@ public Tender getTender() { public void setTender(Tender tender) { this.tender = tender; } - - public Document getDocument() { - return document; - } - - public void setDocument(Document document) { - this.document = document; - } } diff --git a/src/main/java/com/chlorocode/tendertracker/dao/entity/TenderItem.java b/src/main/java/com/chlorocode/tendertracker/dao/entity/TenderItem.java index 0f35fdd..a4a32b0 100644 --- a/src/main/java/com/chlorocode/tendertracker/dao/entity/TenderItem.java +++ b/src/main/java/com/chlorocode/tendertracker/dao/entity/TenderItem.java @@ -4,6 +4,9 @@ import java.util.Date; import java.util.List; +/** + * TenderItem entity. + */ @Entity @Table(name = "tender_item") public class TenderItem { @@ -15,6 +18,7 @@ public class TenderItem { private int uom; private float quantity; private String description; + private int sort; private int createdBy; @Temporal(TemporalType.TIMESTAMP) @@ -63,6 +67,14 @@ public void setDescription(String description) { this.description = description; } + public int getSort() { + return sort; + } + + public void setSort(int sort) { + this.sort = sort; + } + public int getCreatedBy() { return createdBy; } diff --git a/src/main/java/com/chlorocode/tendertracker/dao/entity/TenderVisit.java b/src/main/java/com/chlorocode/tendertracker/dao/entity/TenderVisit.java new file mode 100644 index 0000000..59fc7e3 --- /dev/null +++ b/src/main/java/com/chlorocode/tendertracker/dao/entity/TenderVisit.java @@ -0,0 +1,188 @@ +package com.chlorocode.tendertracker.dao.entity; + +import javax.persistence.*; +import java.util.Date; + +/** + * TenderVisit entity. + */ +@Entity +@Table(name = "tender_visit") +public class TenderVisit { + + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + private int id; + + @ManyToOne + @JoinColumn(name="tender_id") + private Tender tender; + + @Column(name = "visit_date") + private Date visitDate; + + @Column(name = "ip_address") + private String ipAddress; + + private String country; + + @Column(name = "country_code") + private String countryCode; + + private String region; + + @Column(name = "region_name") + private String regionName; + + private String city; + private String zip; + private double lat; + private double lon; + + @Column(name = "time_zone") + private String timeZone; + + private String isp; + private String org; + + @Column(name = "as_no") + private String as; + + private boolean mobile; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public Tender getTender() { + return tender; + } + + public void setTender(Tender tender) { + this.tender = tender; + } + + public Date getVisitDate() { + return visitDate; + } + + public void setVisitDate(Date visitDate) { + this.visitDate = visitDate; + } + + public String getIpAddress() { + return ipAddress; + } + + public void setIpAddress(String ipAddress) { + this.ipAddress = ipAddress; + } + + public String getCountry() { + return country; + } + + public void setCountry(String country) { + this.country = country; + } + + public String getCountryCode() { + return countryCode; + } + + public void setCountryCode(String countryCode) { + this.countryCode = countryCode; + } + + public String getRegion() { + return region; + } + + public void setRegion(String region) { + this.region = region; + } + + public String getRegionName() { + return regionName; + } + + public void setRegionName(String regionName) { + this.regionName = regionName; + } + + public String getCity() { + return city; + } + + public void setCity(String city) { + this.city = city; + } + + public String getZip() { + return zip; + } + + public void setZip(String zip) { + this.zip = zip; + } + + public double getLat() { + return lat; + } + + public void setLat(double lat) { + this.lat = lat; + } + + public double getLon() { + return lon; + } + + public void setLon(double lon) { + this.lon = lon; + } + + public String getTimeZone() { + return timeZone; + } + + public void setTimeZone(String timeZone) { + this.timeZone = timeZone; + } + + public String getIsp() { + return isp; + } + + public void setIsp(String isp) { + this.isp = isp; + } + + public String getOrg() { + return org; + } + + public void setOrg(String org) { + this.org = org; + } + + public String getAs() { + return as; + } + + public void setAs(String as) { + this.as = as; + } + + public boolean isMobile() { + return mobile; + } + + public void setMobile(boolean mobile) { + this.mobile = mobile; + } +} diff --git a/src/main/java/com/chlorocode/tendertracker/dao/entity/Tender_.java b/src/main/java/com/chlorocode/tendertracker/dao/entity/Tender_.java index 1e92c3e..18d90ac 100644 --- a/src/main/java/com/chlorocode/tendertracker/dao/entity/Tender_.java +++ b/src/main/java/com/chlorocode/tendertracker/dao/entity/Tender_.java @@ -1,18 +1,17 @@ package com.chlorocode.tendertracker.dao.entity; -import com.chlorocode.tendertracker.dao.entity.Company; -import com.chlorocode.tendertracker.dao.entity.Tender; -import com.chlorocode.tendertracker.dao.entity.TenderCategory; - import javax.annotation.Generated; -import javax.management.openmbean.OpenDataException; import javax.persistence.metamodel.SingularAttribute; import javax.persistence.metamodel.StaticMetamodel; import java.util.Date; +/** + * This class is used to create specification cirteria for query. + */ @Generated(value = "org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor") @StaticMetamodel(Tender.class) public abstract class Tender_ { + public static volatile SingularAttribute id; public static volatile SingularAttribute title; public static volatile SingularAttribute refNo; public static volatile SingularAttribute status; @@ -20,4 +19,5 @@ public abstract class Tender_ { public static volatile SingularAttribute description; public static volatile SingularAttribute tenderCategory; public static volatile SingularAttribute openDate; + public static volatile SingularAttribute tenderType; } diff --git a/src/main/java/com/chlorocode/tendertracker/dao/entity/UenEntity.java b/src/main/java/com/chlorocode/tendertracker/dao/entity/UenEntity.java index 72f1e7f..cc9d04c 100644 --- a/src/main/java/com/chlorocode/tendertracker/dao/entity/UenEntity.java +++ b/src/main/java/com/chlorocode/tendertracker/dao/entity/UenEntity.java @@ -5,6 +5,7 @@ /** * Created by andy on 16/8/2017. + * UenEntity. */ @Entity @Table(name = "uen_entity") diff --git a/src/main/java/com/chlorocode/tendertracker/dao/entity/User.java b/src/main/java/com/chlorocode/tendertracker/dao/entity/User.java index 7a93d14..b067d06 100644 --- a/src/main/java/com/chlorocode/tendertracker/dao/entity/User.java +++ b/src/main/java/com/chlorocode/tendertracker/dao/entity/User.java @@ -9,6 +9,9 @@ import java.util.LinkedList; import java.util.List; +/** + * User entity. + */ @Entity public class User { @@ -44,6 +47,9 @@ public class User { @OneToMany(mappedBy = "user", cascade = CascadeType.PERSIST) private List tenderCategorySubscriptions; + @OneToMany(mappedBy = "evaluator", cascade = CascadeType.PERSIST) + private List evaluationResults; + private int createdBy; @Temporal(TemporalType.TIMESTAMP) diff --git a/src/main/java/com/chlorocode/tendertracker/dao/entity/UserRole.java b/src/main/java/com/chlorocode/tendertracker/dao/entity/UserRole.java index 0d67b0e..5845902 100644 --- a/src/main/java/com/chlorocode/tendertracker/dao/entity/UserRole.java +++ b/src/main/java/com/chlorocode/tendertracker/dao/entity/UserRole.java @@ -3,6 +3,9 @@ import javax.persistence.*; import java.util.Date; +/** + * UserRole entity. + */ @Entity @Table(name = "user_role") public class UserRole { diff --git a/src/main/java/com/chlorocode/tendertracker/dao/specs/ExternalTenderSpecs.java b/src/main/java/com/chlorocode/tendertracker/dao/specs/ExternalTenderSpecs.java new file mode 100644 index 0000000..83e0584 --- /dev/null +++ b/src/main/java/com/chlorocode/tendertracker/dao/specs/ExternalTenderSpecs.java @@ -0,0 +1,86 @@ +package com.chlorocode.tendertracker.dao.specs; + +import com.chlorocode.tendertracker.dao.entity.ExternalTender; +import com.chlorocode.tendertracker.dao.entity.ExternalTender_; +import com.chlorocode.tendertracker.utils.DateUtility; +import com.chlorocode.tendertracker.utils.TTCommonUtil; +import org.springframework.data.jpa.domain.Specification; + +import javax.persistence.criteria.Predicate; +import java.util.ArrayList; +import java.util.List; + +/** + * Created by Kyaw Min Thu. + * ExternalTenderSpecs is used for create condition for external tender search screen. + */ +public class ExternalTenderSpecs { + + private ExternalTenderSpecs() {} + + /** + * This method is used to create the query for get all open tender. + * + * @return Specification + */ + public static Specification getAllOpenTender() { + return (root, query, cb) -> { + return cb.lessThanOrEqualTo(root.get(ExternalTender_.publishedDate), DateUtility.getCurrentDateTime()); + }; + } + + /** + * This method used to create the query for searching external tender by free text. + * + * @param searchString search free text + * @return Specification + */ + public static Specification byTenderSearchString(String searchString) { + return (root, query, cb) -> { + Predicate openDateFilter = cb.lessThanOrEqualTo(root.get(ExternalTender_.publishedDate), DateUtility.getCurrentDateTime()); + List predicates = new ArrayList<>(); + if (searchString != null && !searchString.isEmpty()) { + predicates.add(cb.like(cb.lower(root.get(ExternalTender_.title)), TTCommonUtil.getContainsLikePattern(searchString))); + predicates.add(cb.like(cb.lower(root.get(ExternalTender_.companyName)), TTCommonUtil.getContainsLikePattern(searchString))); + } + + return cb.and(openDateFilter, cb.or(predicates.toArray(new Predicate[predicates.size()]))); + }; + } + + /** + * This method used to create the query for external tender advanced search. + * + * @param title title of tender + * @param companyName name of company + * @param status status of tender + * @param tenderSource source of external tender + * @param refNo reference number of tender + * @return Specification + */ + public static Specification byTenderSearchCriteria(String title, String companyName, String status + , int tenderSource, String refNo) { + return (root, query, cb) -> { + List predicates = new ArrayList<>(); + + predicates.add(cb.lessThanOrEqualTo(root.get(ExternalTender_.publishedDate), DateUtility.getCurrentDateTime())); + if (title != null && !title.isEmpty()) { + predicates.add(cb.like(cb.lower(root.get(ExternalTender_.title)), TTCommonUtil.getContainsLikePattern(title))); + } + if (companyName != null && !companyName.isEmpty()) { + predicates.add(cb.like(cb.lower(root.get(ExternalTender_.companyName)), TTCommonUtil.getContainsLikePattern(companyName))); + } + if (status != null && !status.isEmpty()) { + predicates.add(cb.like(cb.lower(root.get(ExternalTender_.status)), TTCommonUtil.getContainsLikePattern(status))); + } + if (tenderSource > 0) { + predicates.add(cb.equal(root.get(ExternalTender_.tenderSource), tenderSource)); + } + if(refNo != null && !refNo.isEmpty()){ + predicates.add(cb.like(cb.lower(root.get(ExternalTender_.referenceNo)), TTCommonUtil.getContainsLikePattern(refNo))); + } + + return cb.and(predicates.toArray(new Predicate[predicates.size()])); + }; + } +} diff --git a/src/main/java/com/chlorocode/tendertracker/dao/specs/ProductSpecs.java b/src/main/java/com/chlorocode/tendertracker/dao/specs/ProductSpecs.java new file mode 100644 index 0000000..a61ad28 --- /dev/null +++ b/src/main/java/com/chlorocode/tendertracker/dao/specs/ProductSpecs.java @@ -0,0 +1,90 @@ +package com.chlorocode.tendertracker.dao.specs; + +import com.chlorocode.tendertracker.dao.entity.Company_; +import com.chlorocode.tendertracker.dao.entity.Product; +import com.chlorocode.tendertracker.dao.entity.Product_; +import com.chlorocode.tendertracker.utils.TTCommonUtil; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.data.jpa.domain.Specifications; + +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Predicate; +import javax.persistence.criteria.Root; +import java.util.ArrayList; +import java.util.List; + +/** + * Created by Zaw Min Thant. + * ProductSpecs is used for create condition for product search screen. + */ +public class ProductSpecs { + + /** + * This method is used to create the query for get all product. + * + * @return Specification + */ + public static Specification getAll() { + return ((Root root, CriteriaQuery criteriaQuery, CriteriaBuilder criteriaBuilder) -> { + return criteriaBuilder.and( + criteriaBuilder.equal(root.get(Product_.publish), true), + criteriaBuilder.equal(root.get("status"), 0) + ); + }); + } + + /** + * This method is used to create the query for find product by search string. + * + * @param searchString free search text + * @return Specification + */ + public static Specification byProductSearchString(String searchString) { + return (root, query, cb) -> { + List predicates = new ArrayList<>(); + + if (searchString != null && !searchString.isEmpty()) { + predicates.add(cb.like(cb.lower(root.get(Product_.title)), TTCommonUtil.getContainsLikePattern(searchString))); + predicates.add(cb.like(cb.lower(root.get(Product_.description)), TTCommonUtil.getContainsLikePattern(searchString))); + predicates.add(cb.like(cb.lower(root.get(Product_.company).get(Company_.name)), TTCommonUtil.getContainsLikePattern(searchString))); + } + + return cb.or(predicates.toArray(new Predicate[predicates.size()])); + }; + } + + /** + * This method is used to create the query for search product by search criteria. + * + * @param title title of the product + * @param companyName name of the company + * @return Specification + */ + public static Specification byProductSearchCriteria(String title, String companyName) { + return Specifications.where(getAll()).and(searchProductByTitleAndCompanyName(title, companyName)); + } + + /** + * This method is used to create the query for search product by title and company name. + * + * @param title title of the product + * @param companyName name of the company + * @return Specification + */ + public static Specification searchProductByTitleAndCompanyName(String title, String companyName) { + return (root, query, cb) -> { + List predicates = new ArrayList<>(); + + if (title != null && !title.isEmpty()) { + predicates.add(cb.like(cb.lower(root.get(Product_.title)), TTCommonUtil.getContainsLikePattern(title))); + } + + if (companyName != null && !companyName.isEmpty()) { + predicates.add(cb.like(cb.lower(root.get(Product_.company).get(Company_.name)), TTCommonUtil.getContainsLikePattern(companyName))); + } + + return cb.and(predicates.toArray(new Predicate[predicates.size()])); + }; + } +} diff --git a/src/main/java/com/chlorocode/tendertracker/dao/specs/TenderSpecs.java b/src/main/java/com/chlorocode/tendertracker/dao/specs/TenderSpecs.java index b55228d..0b19451 100644 --- a/src/main/java/com/chlorocode/tendertracker/dao/specs/TenderSpecs.java +++ b/src/main/java/com/chlorocode/tendertracker/dao/specs/TenderSpecs.java @@ -5,46 +5,121 @@ import com.chlorocode.tendertracker.dao.entity.TenderCategory_; import com.chlorocode.tendertracker.dao.entity.Tender_; import com.chlorocode.tendertracker.utils.DateUtility; +import com.chlorocode.tendertracker.utils.TTCommonUtil; import org.springframework.data.jpa.domain.Specification; +import org.springframework.data.jpa.domain.Specifications; +import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.Predicate; import java.util.ArrayList; import java.util.List; +/** + * Created by Kyaw Min Thu. + * TenderSpecs is used for create condition for tender search screen. + */ public class TenderSpecs { private TenderSpecs() {} - public static Specification getAllOpenTender() { - return (root, query, cb) -> { - return cb.lessThanOrEqualTo(root.get(Tender_.openDate), DateUtility.getCurrentDate()); - }; + /** + * This method is used to create the query for home page landing users. + * If user is not login user, show opened and open type tenders. + * If user is login user. Show opened and his company or invited tender or open type tenders. + * + * @param companyId unique identifier of the tender of login user + * @param tenderIds tender id of all invited tenders of login user + * @return Specification + */ + public static Specification getAllOpenTender(int companyId, List tenderIds) { + if (companyId == 0) { + return getDefaultCriteriaSpec(); + } else { + return Specifications.where(getOpenDateCriteria()).and(getLoginUserCriteria(companyId, tenderIds)); + } + } + + /** + * This method is used to create the default criteria of not login user.(Show opened and open type tenders.) + * + * @return Specification + */ + public static Specification getDefaultCriteriaSpec() { + return Specifications.where(getOpenDateCriteria()).and(getOpenTenderTypeCriteria()); } + /** + * This method used to create the query for searching tender by free text. + * If user is not login user, companyId will be 0 and tenderIds will be null. + * + * @param searchString search free text + * @param companyId unique identifier of the tender of login user + * @param tenderIds tender id of all invited tenders of login user + * @return Specification + */ + public static Specification byTenderSearchString(String searchString, int companyId, List tenderIds) { + return Specifications.where(getAllOpenTender(companyId, tenderIds)).and(byTenderSearchString(searchString)); + } + + /** + * This method used to create criteria for finding tender by free text. + * User's searchString will be find in tender title, company name and tender description. + * + * @param searchString search free text + * @return Specification + */ public static Specification byTenderSearchString(String searchString) { return (root, query, cb) -> { - Predicate openDateFilter = cb.lessThanOrEqualTo(root.get(Tender_.openDate), DateUtility.getCurrentDate()); List predicates = new ArrayList<>(); if (searchString != null && !searchString.isEmpty()) { - predicates.add(cb.like(cb.lower(root.get(Tender_.title)), getContainsLikePattern(searchString))); - predicates.add(cb.like(cb.lower(root.get(Tender_.company).get(Company_.name)), getContainsLikePattern(searchString))); - predicates.add(cb.like(cb.lower(root.get(Tender_.description)), getContainsLikePattern(searchString))); + predicates.add(cb.like(cb.lower(root.get(Tender_.title)), TTCommonUtil.getContainsLikePattern(searchString))); + predicates.add(cb.like(cb.lower(root.get(Tender_.company).get(Company_.name)), TTCommonUtil.getContainsLikePattern(searchString))); + predicates.add(cb.like(cb.lower(root.get(Tender_.description)), TTCommonUtil.getContainsLikePattern(searchString))); } - return cb.and(openDateFilter, cb.or(predicates.toArray(new Predicate[predicates.size()]))); + return cb.or(predicates.toArray(new Predicate[predicates.size()])); }; } + /** + * This method used to create the query for advanced search. + * If user is not login user, companyId will be 0 and tenderIds will be null. + * + * @param title title of tender + * @param companyName name of company + * @param tcId category of tender + * @param status status of tender + * @param refNo reference number of tender + * @param companyId unique identifier of the tender of login user + * @param tenderIds tender id of all invited tenders of login user + * @return Specification + */ + public static Specification byTenderSearchCriteria(String title, String companyName, int tcId, int status + , String refNo, int companyId, List tenderIds) { + return Specifications.where(getAllOpenTender(companyId, tenderIds)) + .and(byTenderSearchCriteria(title, companyName, tcId, status, refNo)); + } + + /** + * This method used to create criteria for advance search. + * User's searchString will be find in tender title, company name and tender description. + * + * @param title title of tender + * @param companyName name of company + * @param tcId category of tender + * @param status status of tender + * @param refNo reference number of tender + * @return Specification + */ public static Specification byTenderSearchCriteria(String title, String companyName, int tcId, int status, String refNo) { return (root, query, cb) -> { List predicates = new ArrayList<>(); - predicates.add(cb.lessThanOrEqualTo(root.get(Tender_.openDate), DateUtility.getCurrentDate())); if (title != null && !title.isEmpty()) { - predicates.add(cb.like(cb.lower(root.get(Tender_.title)), getContainsLikePattern(title))); + predicates.add(cb.like(cb.lower(root.get(Tender_.title)), TTCommonUtil.getContainsLikePattern(title))); } if (companyName != null && !companyName.isEmpty()) { - predicates.add(cb.like(cb.lower(root.get(Tender_.company).get(Company_.name)), getContainsLikePattern(companyName))); + predicates.add(cb.like(cb.lower(root.get(Tender_.company).get(Company_.name)), TTCommonUtil.getContainsLikePattern(companyName))); } if (tcId > 0) { predicates.add(cb.equal(root.get(Tender_.tenderCategory).get(TenderCategory_.id), tcId)); @@ -55,45 +130,68 @@ public static Specification byTenderSearchCriteria(String title, String // Added by Andy. if(refNo != null && !refNo.isEmpty()){ - predicates.add(cb.like(cb.lower(root.get(Tender_.refNo)), getContainsLikePattern(refNo))); + predicates.add(cb.like(cb.lower(root.get(Tender_.refNo)), TTCommonUtil.getContainsLikePattern(refNo))); } return cb.and(predicates.toArray(new Predicate[predicates.size()])); }; } - public static Specification isTitleLike(String title) { + /** + * This method is used to create criteria for login user. + * Login user should able to see all of his opened tender and other eligible tender(Opened and open type tenders) + * + * @param companyId unique identifier of the tender of login user + * @param tenderIds tender id of all invited tenders of login user + * @return + */ + private static Specification getLoginUserCriteria(int companyId, List tenderIds) { return (root, query, cb) -> { - String containsLikePattern = getContainsLikePattern(title); - return cb.like(cb.lower(root.get(Tender_.title)), containsLikePattern); - }; - } + List predicates = new ArrayList<>(); - public static Specification isCompanyLike(String company) { - return (root, query, cb) -> { - String containsLikePattern = getContainsLikePattern(company); - return cb.like(cb.lower(root.get(Tender_.company).get(Company_.name)), containsLikePattern); + // 1. Add condition to show all of his company tenders. + if (companyId > 0) { + predicates.add(cb.equal(root.get(Tender_.company).get(Company_.id), companyId)); + } + + // 2. Add condition to show all of his bid tenders. + if (tenderIds != null && tenderIds.size() > 0) { + CriteriaBuilder.In inTenderIds = cb.in(root.get(Tender_.id)); + for (Integer id : tenderIds) { + inTenderIds.value(id); + } + predicates.add(inTenderIds); + } + + // 3. Show open tender type. + predicates.add(cb.equal(root.get(Tender_.tenderType), 1)); + // or(1,2,3) + return cb.or(predicates.toArray(new Predicate[predicates.size()])); }; } - public static Specification isEqualTenderCategory(int tcId) { + /** + * This method is used to create criteria for getting all opened tender. + * + * @return Specification + */ + private static Specification getOpenDateCriteria() { return (root, query, cb) -> { - return cb.equal(root.get(Tender_.tenderCategory).get(TenderCategory_.id), tcId); + // show openDate isEqualStatus(int status) { + /** + * This method is used to create for getting all open type tenders. + * + * @return Specification + */ + private static Specification getOpenTenderTypeCriteria() { return (root, query, cb) -> { - return cb.equal(root.get(Tender_.status), status); + // show only open tender type. + return cb.equal(root.get(Tender_.tenderType), 1); }; } - private static String getContainsLikePattern(String searchTerm) { - if (searchTerm == null || searchTerm.isEmpty()) { - return "%"; - } - else { - return "%" + searchTerm.toLowerCase() + "%"; - } - } } diff --git a/src/main/java/com/chlorocode/tendertracker/exception/ApplicationException.java b/src/main/java/com/chlorocode/tendertracker/exception/ApplicationException.java index 60c8c3d..d0b5786 100644 --- a/src/main/java/com/chlorocode/tendertracker/exception/ApplicationException.java +++ b/src/main/java/com/chlorocode/tendertracker/exception/ApplicationException.java @@ -1,5 +1,9 @@ package com.chlorocode.tendertracker.exception; +/** + * Exception for business logic validation purpose. + * This exception extends standard RuntimeException. + */ public class ApplicationException extends RuntimeException { public ApplicationException(String message) { diff --git a/src/main/java/com/chlorocode/tendertracker/exception/ResourceNotFoundException.java b/src/main/java/com/chlorocode/tendertracker/exception/ResourceNotFoundException.java index aee79c8..788ced0 100644 --- a/src/main/java/com/chlorocode/tendertracker/exception/ResourceNotFoundException.java +++ b/src/main/java/com/chlorocode/tendertracker/exception/ResourceNotFoundException.java @@ -3,6 +3,9 @@ import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; +/** + * Exception for REST controller to give HTTP 404 response code. + */ @ResponseStatus(value = HttpStatus.NOT_FOUND) public class ResourceNotFoundException extends RuntimeException { diff --git a/src/main/java/com/chlorocode/tendertracker/filter/AuthorizationFilter.java b/src/main/java/com/chlorocode/tendertracker/filter/AuthorizationFilter.java index 3e2580f..bb9066f 100644 --- a/src/main/java/com/chlorocode/tendertracker/filter/AuthorizationFilter.java +++ b/src/main/java/com/chlorocode/tendertracker/filter/AuthorizationFilter.java @@ -18,9 +18,21 @@ import java.io.IOException; import java.util.Collection; +/** + * This class is used to perform authentication and authorization filter check for all pages in the system. + */ @Component public class AuthorizationFilter extends GenericFilterBean { + /** + * This method is used for filter the authorization. + * + * @param servletRequest ServletRequest + * @param servletResponse ServletResponse + * @param filterChain FilterChain + * @throws IOException IOException + * @throws ServletException ServletException + */ @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest; @@ -41,10 +53,11 @@ public void doFilter(ServletRequest servletRequest, ServletResponse servletRespo Collection authorities = auth.getAuthorities(); boolean isCompanyAdmin = authorities.contains(new SimpleGrantedAuthority("ROLE_ADMIN")); boolean isPreparer = authorities.contains(new SimpleGrantedAuthority("ROLE_PREPARER")); + boolean isSubmitter = authorities.contains(new SimpleGrantedAuthority("ROLE_SUBMITTER")); boolean isSystemAdmin = authorities.contains(new SimpleGrantedAuthority("ROLE_SYS_ADMIN")); - // Reject access if not Company Admin, System Admin, or Preparer - if (!isCompanyAdmin && !isSystemAdmin && !isPreparer) { + // Reject access if not Company Admin, System Admin, Submitter, or Preparer + if (!isCompanyAdmin && !isSystemAdmin && !isPreparer && !isSubmitter) { ((HttpServletResponse)servletResponse).setStatus(HttpServletResponse.SC_FORBIDDEN); return; } diff --git a/src/main/java/com/chlorocode/tendertracker/logging/TTLogger.java b/src/main/java/com/chlorocode/tendertracker/logging/TTLogger.java index af6344b..2c0e1f9 100644 --- a/src/main/java/com/chlorocode/tendertracker/logging/TTLogger.java +++ b/src/main/java/com/chlorocode/tendertracker/logging/TTLogger.java @@ -3,6 +3,9 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +/** + * This class is used to perform logging. + */ public class TTLogger { private static final Logger logger; diff --git a/src/main/java/com/chlorocode/tendertracker/props/MailProperties.java b/src/main/java/com/chlorocode/tendertracker/props/MailProperties.java index 61b86f0..c901268 100644 --- a/src/main/java/com/chlorocode/tendertracker/props/MailProperties.java +++ b/src/main/java/com/chlorocode/tendertracker/props/MailProperties.java @@ -2,6 +2,9 @@ import org.springframework.boot.context.properties.ConfigurationProperties; +/** + * This class is used to get mail properties value. + */ @ConfigurationProperties(prefix = "mail") public class MailProperties { @@ -10,16 +13,38 @@ public class MailProperties { private String subUpdateTender; private String subAddCorrigendum; private String subCreateTender; + private String subClosedTender; private String subCompanyReview; private String subCompanyRegistered; + private String subTenderAwarded; + + private String subCompanyBlacklisted; + + private String subMilestoneApproach; + private String subAppealCreate; + private String subAppealUpdate; + private String subAppealAccepted; + private String subAppealRejected; + private String templateOTP; private String templateWelcome; private String templateUpdateTender; private String templateAddCorrigendum; private String templateCreateTender; + private String templateClosedTender; private String templateCompanyApproved; private String templateCompanyRejected; private String templateCompanyRegistered; + private String templateTenderAwarded; + + private String templateCompanyBlacklisted; + + private String templateMilestoneApproach; + private String templateAppealCreate; + private String templateAppealUpdate; + private String templateAppealAccepted; + private String templateAppealRejected; + public String getSubOTP() { return subOTP; @@ -140,57 +165,134 @@ public String getTemplateCompanyRegistered() { public void setTemplateCompanyRegistered(String templateCompanyRegistered) { this.templateCompanyRegistered = templateCompanyRegistered; } - // private String subjectOTP; -// public static final String OTP_TEMPLATE = "" -// + "

Dear %s,

" -// + "

Please click on following link to reset password for your account." -// + "
\"http://localhost:8080/resetPassword/%s/%s\"

" -// + "

Regards,
Tender Tracker

" -// + ""; -// -// @Value("${subject.welcome_mail}") -// private String subjectWelcome; -// public static final String WELCOME_TEMPLATE = "" -// + "

Welcome to Tender Tracker.

" -// + "

Hi %s, your account creation is completed.

" -// + "

Regards,
Tender Tracker

" -// + ""; -// -// @Value("${subject.update_tender_mail}") -// private String subjectUpdateTender; -// public static final String UPDATE_TENDER_TEMPLATE = "" -// + "

Tender \"%s\" has been updated.

" -// + "

Please see more information on following link." -// + "
\"http://localhost:8080/tender/%s\"

" -// + "

Regards,
Tender Tracker

" -// + ""; -// -// @Value("${subject.add_corrigendum_mail}") -// private String subjectAddCorrigendum; -// public static final String ADD_CORRIGENDUM_TEMPLATE = "" -// + "

New corrigendum add into the tender \"%s\".

" -// + "

Please see more information on following link." -// + "
\"http://localhost:8080/tender/%s\"

" -// + "

Regards,
Tender Tracker

" -// + ""; -// -// @Value("${subject.create_tender_mail}") -// private String subjectCreateTender; -// public static final String CREATE_TENDER_TEMPLATE = "" -// + "

Tender \"%s\" has been created.

" -// + "

Please see more information on following link." -// + "
\"http://localhost:8080/tender/%s\"

" -// + "

Regards,
Tender Tracker

" -// + ""; -// -// @Value("${subject.company_review_mail}") -// private String subjectCompanyReview; -// public static final String COMPANY_APPROVE_TEMPLATE = "" -// + "

Congratulation, your company \"%s\" registration request has been approved.

" -// + "

Regards,
Tender Tracker

" -// + ""; -// public static final String COMPANY_REJECT_TEMPLATE = "" -// + "

Sorry, your company \"%s\" registration request has been rejected.

" -// + "

Regards,
Tender Tracker

" -// + ""; + + public String getSubClosedTender() { + return subClosedTender; + } + + public void setSubClosedTender(String subClosedTender) { + this.subClosedTender = subClosedTender; + } + + public String getTemplateClosedTender() { + return templateClosedTender; + } + + public void setTemplateClosedTender(String templateClosedTender) { + this.templateClosedTender = templateClosedTender; + } + + + public String getSubCompanyBlacklisted() { + return subCompanyBlacklisted; + } + + public void setSubCompanyBlacklisted(String subCompanyBlacklisted) { + this.subCompanyBlacklisted = subCompanyBlacklisted; + } + + public String getTemplateCompanyBlacklisted() { + return templateCompanyBlacklisted; + } + + public void setTemplateCompanyBlacklisted(String templateCompanyBlacklisted) { + this.templateCompanyBlacklisted = templateCompanyBlacklisted; + } + + public String getSubMilestoneApproach() { + return subMilestoneApproach; + } + + public void setSubMilestoneApproach(String subMilestoneApproach) { + this.subMilestoneApproach = subMilestoneApproach; + } + + public String getSubAppealCreate() { + return subAppealCreate; + } + + public void setSubAppealCreate(String subAppealCreate) { + this.subAppealCreate = subAppealCreate; + } + + public String getSubAppealUpdate() { + return subAppealUpdate; + } + + public void setSubAppealUpdate(String subAppealUpdate) { + this.subAppealUpdate = subAppealUpdate; + } + + public String getTemplateMilestoneApproach() { + return templateMilestoneApproach; + } + + public void setTemplateMilestoneApproach(String templateMilestoneApproach) { + this.templateMilestoneApproach = templateMilestoneApproach; + } + + public String getTemplateAppealCreate() { + return templateAppealCreate; + } + + public void setTemplateAppealCreate(String templateAppealCreate) { + this.templateAppealCreate = templateAppealCreate; + } + + public String getTemplateAppealUpdate() { + return templateAppealUpdate; + } + + public void setTemplateAppealUpdate(String templateAppealUpdate) { + this.templateAppealUpdate = templateAppealUpdate; + + } + + public String getSubAppealAccepted() { + return subAppealAccepted; + } + + public void setSubAppealAccepted(String subAppealAccepted) { + this.subAppealAccepted = subAppealAccepted; + } + + public String getSubAppealRejected() { + return subAppealRejected; + } + + public void setSubAppealRejected(String subAppealRejected) { + this.subAppealRejected = subAppealRejected; + } + + public String getTemplateAppealAccepted() { + return templateAppealAccepted; + } + + public void setTemplateAppealAccepted(String templateAppealAccepted) { + this.templateAppealAccepted = templateAppealAccepted; + } + + public String getTemplateAppealRejected() { + return templateAppealRejected; + } + + public void setTemplateAppealRejected(String templateAppealRejected) { + this.templateAppealRejected = templateAppealRejected; + } + + public String getSubTenderAwarded() { + return subTenderAwarded; + } + + public void setSubTenderAwarded(String subTenderAwarded) { + this.subTenderAwarded = subTenderAwarded; + } + + public String getTemplateTenderAwarded() { + return templateTenderAwarded; + } + + public void setTemplateTenderAwarded(String templateTenderAwarded) { + this.templateTenderAwarded = templateTenderAwarded; + } } diff --git a/src/main/java/com/chlorocode/tendertracker/scheduler/TenderScheduledTask.java b/src/main/java/com/chlorocode/tendertracker/scheduler/TenderScheduledTask.java new file mode 100644 index 0000000..885f8c9 --- /dev/null +++ b/src/main/java/com/chlorocode/tendertracker/scheduler/TenderScheduledTask.java @@ -0,0 +1,84 @@ +package com.chlorocode.tendertracker.scheduler; + +import com.chlorocode.tendertracker.dao.ExternalTenderDAO; +import com.chlorocode.tendertracker.dao.TenderDAO; +import com.chlorocode.tendertracker.logging.TTLogger; +import com.chlorocode.tendertracker.service.MilestoneService; +import com.chlorocode.tendertracker.service.TenderSubscriptionService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import javax.transaction.Transactional; +import java.util.Date; + +/** + * This class is used to configure all the spring scheduled task. + */ +@Component +public class TenderScheduledTask { + + private String className; + private ExternalTenderDAO externalTenderDAO; + private TenderDAO tenderDAO; + private MilestoneService milestoneService; + private TenderSubscriptionService tenderSubscriptionService; + + /** + * Constructor + * + * @param externalTenderDAO ExternalTenderDAO + * @param tenderDAO TenderDAO + * @param milestoneService MilestoneService + * @param tenderSubscriptionService TenderSubscriptionService + */ + @Autowired + public TenderScheduledTask(ExternalTenderDAO externalTenderDAO, TenderDAO tenderDAO + , MilestoneService milestoneService, TenderSubscriptionService tenderSubscriptionService) { + this.className = this.getClass().getName(); + this.externalTenderDAO = externalTenderDAO; + this.tenderDAO = tenderDAO; + this.milestoneService = milestoneService; + this.tenderSubscriptionService = tenderSubscriptionService; + } + + /** + * This is the job to auto closed expired tender. + */ + @Scheduled(cron="0 0 3 * * *", zone = "Asia/Singapore") // Daily every 3 AM Singapore Time + @Transactional + public void tenderAutoClose() { + TTLogger.info(className, "Auto Close status update for External Tender"); + Date currentDate = new Date(); + externalTenderDAO.autoCloseExternalTender(currentDate); + TTLogger.info(className, "Completed Auto Close status update for External Tender"); + + TTLogger.info(className, "Auto Close status update for Tender"); + tenderDAO.autoCloseTender(currentDate); + TTLogger.info(className, "Completed Auto Close status update for Tender"); + } + + /** + * This is the job to send email notification to company administrator that tender has been closed and ready for evaluation. + */ + @Scheduled(cron="0 * * * * *", zone = "Asia/Singapore") // Will work at the start of every minute. + @Transactional + public void autoNotifyTenderClose() { + TTLogger.info(className, "Auto notify tender close."); + //Notify company administrator that the tender has closed and ready for evaluation."); + tenderSubscriptionService.autoCloseTenderAndNotify(); + TTLogger.info(className, "Completed tender close and notify."); + } + + /** + * This is the job to notify company administrator that the tender milestone is approaching. + */ + @Scheduled(cron="0 * * * * *", zone = "Asia/Singapore") // Will work at the start of every minute. + @Transactional + public void autoNotifyApproachMilestone() { + TTLogger.info(className, "Auto notify approach milestone."); + //Notify company administrator that the milestone of the company tender has been approaching."); + milestoneService.notifyApproachMilestone(); + TTLogger.info(className, "Completed approach milestone notify."); + } +} diff --git a/src/main/java/com/chlorocode/tendertracker/service/AuthService.java b/src/main/java/com/chlorocode/tendertracker/service/AuthService.java index 4b78eb7..1ab107c 100644 --- a/src/main/java/com/chlorocode/tendertracker/service/AuthService.java +++ b/src/main/java/com/chlorocode/tendertracker/service/AuthService.java @@ -2,6 +2,9 @@ import org.springframework.security.core.userdetails.UserDetailsService; +/** + * Interface service for authentication. + */ public interface AuthService extends UserDetailsService { } diff --git a/src/main/java/com/chlorocode/tendertracker/service/AuthServiceImpl.java b/src/main/java/com/chlorocode/tendertracker/service/AuthServiceImpl.java index 1c3804d..4f64862 100644 --- a/src/main/java/com/chlorocode/tendertracker/service/AuthServiceImpl.java +++ b/src/main/java/com/chlorocode/tendertracker/service/AuthServiceImpl.java @@ -17,6 +17,9 @@ import java.util.List; import java.util.stream.Collectors; +/** + * Service implementation of AuthService. + */ @Service public class AuthServiceImpl implements AuthService { @@ -24,6 +27,12 @@ public class AuthServiceImpl implements AuthService { private UserDAO userDAO; private UserRoleDAO userRoleDAO; + /** + * Constructor. + * + * @param userDAO UserDAO + * @param userRoleDAO UserRoleDAO + */ @Autowired public AuthServiceImpl(UserDAO userDAO, UserRoleDAO userRoleDAO) { this.className = this.getClass().getName(); @@ -31,6 +40,13 @@ public AuthServiceImpl(UserDAO userDAO, UserRoleDAO userRoleDAO) { this.userRoleDAO = userRoleDAO; } + /** + * This method is used to override the default authentication method and implement custom authentication and authorization. + * + * @param email user email + * @return UserDetails + * @throws UsernameNotFoundException UsernameNotFoundException + */ @Override public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException { TTLogger.info(className, email + " attempt login"); diff --git a/src/main/java/com/chlorocode/tendertracker/service/BidService.java b/src/main/java/com/chlorocode/tendertracker/service/BidService.java index 40c3cab..7e8a4d7 100644 --- a/src/main/java/com/chlorocode/tendertracker/service/BidService.java +++ b/src/main/java/com/chlorocode/tendertracker/service/BidService.java @@ -1,14 +1,72 @@ package com.chlorocode.tendertracker.service; import com.chlorocode.tendertracker.dao.entity.Bid; +import com.chlorocode.tendertracker.dao.entity.BidItem; import org.springframework.web.multipart.MultipartFile; import java.util.List; +/** + * Interface service for bid. + */ public interface BidService { + /** + * This method is used to find bid by id. + * + * @param id unique identifier of thi bid + * @return Bid + */ + Bid findById(int id); + + /** + * This method is used to save bid. + * + * @param bid bid object to be saved + * @param attachments bid attachments to be saved + * @return Bid + */ Bid saveBid(Bid bid, List attachments); + /** + * This method is used to find a Bid by tender and company who submit the bid. + * + * @param companyId unique identifier of the company hwo submit the bid + * @param tenderId unique identifier of the tender + * @return Bid + */ Bid findBidByCompanyAndTender(int companyId, int tenderId); + /** + * This method is used to find a list of bids submitted by a particular company. + * + * @param companyId unique identifier of the company + * @return list of Bid + */ + List findBidByCompany(int companyId); + + /** + * This method is used to find a list of bid for a particular tender. + * + * @param tenderId unique identifier of the tender + * @return list of bid + */ + List findBidByTender(int tenderId); + + /** + * This method is used to find bid item for particular bid. + * + * @param id unique identifier of the tender + * @return bid item + */ + BidItem findBidItemById(int id); + + /** + * This method is used to find bid item for particular bid. + * + * @param bidItem bid item object + * @return bid item + */ + BidItem updateBid(BidItem bidItem); + } diff --git a/src/main/java/com/chlorocode/tendertracker/service/BidServiceImpl.java b/src/main/java/com/chlorocode/tendertracker/service/BidServiceImpl.java index 1e0adfd..b266249 100644 --- a/src/main/java/com/chlorocode/tendertracker/service/BidServiceImpl.java +++ b/src/main/java/com/chlorocode/tendertracker/service/BidServiceImpl.java @@ -1,10 +1,11 @@ package com.chlorocode.tendertracker.service; import com.chlorocode.tendertracker.dao.BidDAO; -import com.chlorocode.tendertracker.dao.DocumentDAO; +import com.chlorocode.tendertracker.dao.BidDocumentDAO; +import com.chlorocode.tendertracker.dao.BidItemDAO; import com.chlorocode.tendertracker.dao.entity.Bid; import com.chlorocode.tendertracker.dao.entity.BidDocument; -import com.chlorocode.tendertracker.dao.entity.Document; +import com.chlorocode.tendertracker.dao.entity.BidItem; import com.chlorocode.tendertracker.exception.ApplicationException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -15,18 +16,36 @@ import java.util.Date; import java.util.List; +/** + * Service implementation of BidService. + */ @Service public class BidServiceImpl implements BidService { private BidDAO bidDAO; - private DocumentDAO documentDAO; + private BidDocumentDAO bidDocumentDAO; private S3Wrapper s3Wrapper; + private BidItemDAO bidItemDAO; + /** + * Constructor. + * + * @param bidDAO BidDAO + * @param bidDocumentDAO BidDocumentDAO + * @param s3Wrapper S3Wrapper + * @param bidItemDAO BidItemDAO + */ @Autowired - public BidServiceImpl(BidDAO bidDAO, DocumentDAO documentDAO, S3Wrapper s3Wrapper) { + public BidServiceImpl(BidDAO bidDAO, BidDocumentDAO bidDocumentDAO, S3Wrapper s3Wrapper,BidItemDAO bidItemDAO) { this.bidDAO = bidDAO; - this.documentDAO = documentDAO; + this.bidDocumentDAO = bidDocumentDAO; this.s3Wrapper = s3Wrapper; + this.bidItemDAO = bidItemDAO; + } + + @Override + public Bid findById(int id) { + return bidDAO.findOne(id); } @Override @@ -49,19 +68,17 @@ public Bid saveBid(Bid bid, List attachments) { } // Save to DB - Document doc = new Document(); + BidDocument doc = new BidDocument(); doc.setName(f.getOriginalFilename()); doc.setLocation(bucketPath); - doc.setType(2); doc.setCreatedBy(bid.getCreatedBy()); doc.setCreatedDate(new Date()); doc.setLastUpdatedBy(bid.getLastUpdatedBy()); doc.setLastUpdatedDate(new Date()); - documentDAO.save(doc); + doc.setBid(bid); + bidDocumentDAO.save(doc); - BidDocument bidDocument = new BidDocument(); - bidDocument.setDocument(doc); - bid.addBidDocument(bidDocument); + bid.addBidDocument(doc); } return result; @@ -71,4 +88,24 @@ public Bid saveBid(Bid bid, List attachments) { public Bid findBidByCompanyAndTender(int companyId, int tenderId) { return bidDAO.findBidByCompanyAndTender(companyId,tenderId); } + + @Override + public List findBidByCompany(int companyId) { + return bidDAO.findBidByCompany(companyId); + } + + @Override + public List findBidByTender(int tenderId) { + return bidDAO.findBidByTender(tenderId); + } + + @Override + public BidItem findBidItemById(int id) { + return bidItemDAO.findOne(id); + } + + @Override + public BidItem updateBid(BidItem bidItem) { + return bidItemDAO.saveAndFlush(bidItem); + } } diff --git a/src/main/java/com/chlorocode/tendertracker/service/ClarificationService.java b/src/main/java/com/chlorocode/tendertracker/service/ClarificationService.java index d96a0b7..1c8be6e 100644 --- a/src/main/java/com/chlorocode/tendertracker/service/ClarificationService.java +++ b/src/main/java/com/chlorocode/tendertracker/service/ClarificationService.java @@ -1,18 +1,54 @@ package com.chlorocode.tendertracker.service; import com.chlorocode.tendertracker.dao.entity.Clarification; -import com.chlorocode.tendertracker.dao.entity.Tender; import java.util.List; /** - * Created by andy on 8/8/2017. + * Service interface for tender clarification. */ public interface ClarificationService { + + /** + * This method is used to find the list of clarifications for a particular tender. + * + * @param tenderId unique identifier of the tender + * @return list of Clarification + */ List findClarificationByTenderId(int tenderId); + + /** + * This method is used to list all clarifications. + * + * @return list of Clarification + */ List findAllClarification(); + + /** + * This method is used to update tender clarification with response. + * + * @param id unique identifier of the clarification + * @param response new response to be updated + * @return Clarification + */ Clarification updateReponse(int id, String response); + + /** + * This method is used to find a tender clarification response by clarification id. + * + * @param id unique identifier of the clarification + * @return Clarification + */ Clarification findById(int id); + + /** + * This method is used to save a new tender clarification. + * + * @param classification clarification message + * @param tenderId unique identifier of the tender + * @param companyId unique identifier of the company who submit the clarification + * @return Clarification + */ Clarification create(String classification, int tenderId, int companyId); } diff --git a/src/main/java/com/chlorocode/tendertracker/service/ClarificationServiceImpl.java b/src/main/java/com/chlorocode/tendertracker/service/ClarificationServiceImpl.java index 1756d61..18acac2 100644 --- a/src/main/java/com/chlorocode/tendertracker/service/ClarificationServiceImpl.java +++ b/src/main/java/com/chlorocode/tendertracker/service/ClarificationServiceImpl.java @@ -10,12 +10,11 @@ import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Service; -import javax.validation.constraints.Null; import java.util.Date; import java.util.List; /** - * Created by andy on 8/8/2017. + * Service implementation of ClarificationService. */ @Service public class ClarificationServiceImpl implements ClarificationService{ @@ -23,6 +22,11 @@ public class ClarificationServiceImpl implements ClarificationService{ private ClarificationDAO clariDao; private String className; + /** + * Constructor. + * + * @param clariDao ClarificationDAO + */ @Autowired public ClarificationServiceImpl(ClarificationDAO clariDao){ this.className = this.getClass().getName(); diff --git a/src/main/java/com/chlorocode/tendertracker/service/CodeValueService.java b/src/main/java/com/chlorocode/tendertracker/service/CodeValueService.java index b7fe956..2a5b726 100644 --- a/src/main/java/com/chlorocode/tendertracker/service/CodeValueService.java +++ b/src/main/java/com/chlorocode/tendertracker/service/CodeValueService.java @@ -7,19 +7,79 @@ import java.util.List; import java.util.Map; +/** + * Service interface for code value. + */ public interface CodeValueService { + /** + * This method is used to get all CodeValue for a particular type. + * + * @param type code value type + * @return list of CodeValue + */ List getByType(String type); + /** + * This method is used to get a code value description based on code value type and code. + * + * @param type code value type + * @param code code value code + * @return String + */ String getDescription(String type, int code); + /** + * This method is used to get all tender categories. + * + * @return list of TenderCategory + */ List getAllTenderCategories(); + /** + * This method is used to get a tender category by tender category id. + * + * @param id unique identifier of the tender category + * @return TenderCategory + */ TenderCategory getTenderCategoryById(int id); + /** + * This method is used to get all tender order by search criteria. + * e.g. order by title, opening date. + * + * @return Map of criteria name and description to be displayed + */ Map getTenderOrderBy(); + /** + * This method is used to get all tender order mode search criteria. + * e.g. order ascending / descending. + * + * @return Map of order mode and description to be displayed + */ Map getTenderOrderMode(); + /** + * This method is used to get all product order by search criteria. + * e.g. order by title, price. + * + * @return Map of criteria name and description to be displayed + */ + Map getProductOrderBy(); + + /** + * This method is used to get all tender order mode search criteria. + * e.g. order ascending / descending. + * + * @return Map of order mode and description to be displayed + */ + Map getProductOrderMode(); + + /** + * This method is used to retrieve all countries from database. + * + * @return List of Country + */ List getAllCountries(); } diff --git a/src/main/java/com/chlorocode/tendertracker/service/CodeValueServiceImpl.java b/src/main/java/com/chlorocode/tendertracker/service/CodeValueServiceImpl.java index 40772cb..5033f44 100644 --- a/src/main/java/com/chlorocode/tendertracker/service/CodeValueServiceImpl.java +++ b/src/main/java/com/chlorocode/tendertracker/service/CodeValueServiceImpl.java @@ -2,6 +2,8 @@ import com.chlorocode.tendertracker.constants.TTConstants; import com.chlorocode.tendertracker.dao.CodeValueDAO; +import com.chlorocode.tendertracker.dao.CountryDAO; +import com.chlorocode.tendertracker.dao.TenderCategoryDAO; import com.chlorocode.tendertracker.dao.entity.CodeValue; import com.chlorocode.tendertracker.dao.entity.Country; import com.chlorocode.tendertracker.dao.entity.TenderCategory; @@ -12,14 +14,28 @@ import java.util.List; import java.util.Map; +/** + * Service implementation of CodeValueService. + */ @Service public class CodeValueServiceImpl implements CodeValueService { private CodeValueDAO codeValueDAO; + private TenderCategoryDAO tenderCategoryDAO; + private CountryDAO countryDAO; + /** + * Constructor. + * + * @param codeValueDAO CodeValueDAO + * @param tenderCategoryDAO TenderCategoryDAO + * @param countryDAO CountryDAO + */ @Autowired - public CodeValueServiceImpl(CodeValueDAO codeValueDAO) { + public CodeValueServiceImpl(CodeValueDAO codeValueDAO, TenderCategoryDAO tenderCategoryDAO, CountryDAO countryDAO) { this.codeValueDAO = codeValueDAO; + this.tenderCategoryDAO = tenderCategoryDAO; + this.countryDAO = countryDAO; } @Override @@ -34,12 +50,12 @@ public String getDescription(String type, int code) { @Override public List getAllTenderCategories() { - return codeValueDAO.getAllTenderCategories(); + return tenderCategoryDAO.getAllTenderCategories(); } @Override public TenderCategory getTenderCategoryById(int id) { - return codeValueDAO.getTenderCategoryById(id); + return tenderCategoryDAO.getTenderCategoryById(id); } @Override @@ -61,8 +77,27 @@ public Map getTenderOrderMode() { return orderMode; } + @Override + public Map getProductOrderBy() { + Map orderBy = new HashMap<>(); + orderBy.put(TTConstants.TITLE, TTConstants.LBL_TITLE); + orderBy.put(TTConstants.CREATE_DATE, TTConstants.LBL_CREATE_DATE); + orderBy.put(TTConstants.PRICE, TTConstants.LBL_PRICE); + + return orderBy; + } + + @Override + public Map getProductOrderMode() { + Map orderMode = new HashMap<>(); + orderMode.put(TTConstants.ASC, TTConstants.LBL_ASC); + orderMode.put(TTConstants.DESC, TTConstants.LBL_DESC); + + return orderMode; + } + @Override public List getAllCountries() { - return codeValueDAO.getAllCountries(); + return countryDAO.getAllCountries(); } } diff --git a/src/main/java/com/chlorocode/tendertracker/service/CompanyService.java b/src/main/java/com/chlorocode/tendertracker/service/CompanyService.java index 2c05af9..e8fefc1 100644 --- a/src/main/java/com/chlorocode/tendertracker/service/CompanyService.java +++ b/src/main/java/com/chlorocode/tendertracker/service/CompanyService.java @@ -5,17 +5,98 @@ import java.util.List; +/** + * Service interface for company. + */ public interface CompanyService { - Company registerCompany(Company companyRegistration); + /** + * This method is used to save company registration record. + * + * @param companyRegistration company object to be saved + * @return String + */ + String registerCompany(Company companyRegistration); + + /** + * This method is used to find company with pending approval status. + * + * @return list of Company + */ List findCompanyPendingApproval(); + + /** + * This method is used to find company registration record by company id. + * + * @param id unique identifier of the company + * @return CompanyRegistrationDetailsDTO + * @see com.chlorocode.tendertracker.dao.dto.CompanyRegistrationDTO + */ CompanyRegistrationDetailsDTO findCompanyRegistrationById(int id); + + /** + * This method is used to approve company registration. + * + * @param id unique identifier of the company + * @param approvedBy user id who approve the company + */ void approveCompanyRegistration(int id, int approvedBy); + + /** + * This method is used to reject company registration. + * + * @param id unique identifier of the company + * @param rejectedBy user id who reject the company + */ void rejectCompanyRegistration(int id, int rejectedBy); + /** + * This method is used to blacklist company. + * + * @param id unique identifier of the company + * @param blacklistedBy user id who blacklist the company + * @return boolean + */ + boolean blacklistCompany(int id, int blacklistedBy); + + /** + * This method is used to remove company blacklist. + * + * @param id unique identifier of the company + * @param unblacklistedBy user id who remove the company blacklist + * @return boolean + */ + boolean unblacklistCompany(int id, int unblacklistedBy); + + /** + * This method is used to get a company by company id. + * + * @param id unique identifier of the company + * @return Company + */ Company findById(int id); + + /** + * This method is used to update company. + * + * @param company company object to be updated + * @return Company + */ Company updateCompany(Company company); + + /** + * This method is used to find company by UEN. + * + * @param uen uen no + * @return list of Company + */ List findCompanyByUen(String uen); + /** + * This method is used to find company by creator. + * + * @param userId unique identifier of the user + * @return list of Company + */ List findCompanyByCreatedBy(int userId); } diff --git a/src/main/java/com/chlorocode/tendertracker/service/CompanyServiceImpl.java b/src/main/java/com/chlorocode/tendertracker/service/CompanyServiceImpl.java index 610498f..bf2f7d2 100644 --- a/src/main/java/com/chlorocode/tendertracker/service/CompanyServiceImpl.java +++ b/src/main/java/com/chlorocode/tendertracker/service/CompanyServiceImpl.java @@ -5,15 +5,20 @@ import com.chlorocode.tendertracker.dao.dto.CompanyRegistrationDetailsDTO; import com.chlorocode.tendertracker.dao.entity.Company; import com.chlorocode.tendertracker.dao.entity.Role; +import com.chlorocode.tendertracker.dao.entity.UenEntity; import com.chlorocode.tendertracker.dao.entity.User; import com.chlorocode.tendertracker.exception.ApplicationException; import com.chlorocode.tendertracker.service.notification.NotificationService; import com.chlorocode.tendertracker.service.notification.NotificationServiceImpl; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import javax.transaction.Transactional; import java.util.*; +/** + * Implementation of CompanyService. + */ @Service public class CompanyServiceImpl implements CompanyService { @@ -23,19 +28,42 @@ public class CompanyServiceImpl implements CompanyService { private UserService userService; private UserRoleService userRoleService; private NotificationService notificationService; - - public CompanyServiceImpl(CompanyDAO companyDAO, - CodeValueService codeValueService, UserService userService - , UserRoleService userRoleService, NotificationService notificationService) { + private UenEntityService uenEntService; + + /** + * Constructor. + * + * @param companyDAO CompanyDAO + * @param codeValueService CodeValueService + * @param userService UserService + * @param userRoleService UserRoleService + * @param notificationService NotificationService + * @param uenEntService UenEntityService + */ + @Autowired + public CompanyServiceImpl(CompanyDAO companyDAO, CodeValueService codeValueService, UserService userService + , UserRoleService userRoleService, NotificationService notificationService + , UenEntityService uenEntService) { this.companyDAO = companyDAO; this.codeValueService = codeValueService; this.userService = userService; this.userRoleService = userRoleService; this.notificationService = notificationService; + this.uenEntService = uenEntService; } @Override - public Company registerCompany(Company companyRegistration) throws ApplicationException { + public String registerCompany(Company companyRegistration) throws ApplicationException { + List compList = findCompanyByUen(companyRegistration.getUen()); + + if(compList != null && compList.size() > 0){ + return "This company UEN already exist"; + } + + UenEntity uenEnt = uenEntService.findByUen(companyRegistration.getUen()); + if (uenEnt == null) { + return "Invalid UEN"; + } if (!companyRegistration.isPostalCodeValid()) { throw new ApplicationException("Invalid postal code"); } @@ -51,7 +79,7 @@ public Company registerCompany(Company companyRegistration) throws ApplicationEx params.put(TTConstants.PARAM_EMAIL, user.getEmail()); notificationService.sendNotification(NotificationServiceImpl.NOTI_MODE.company_reg_noti, params); - return company; + return null; } @Override @@ -84,7 +112,19 @@ public CompanyRegistrationDetailsDTO findCompanyRegistrationById(int id) { reg.setApplicant(userService.findById(company.getCreatedBy())); reg.setApplicationDate(company.getCreatedDate()); reg.setPrincipleActivity(company.getPrincpleBusinessActivity()); + reg.setActive(company.isActive()); + if(company.getStatus() == 1){ + reg.setStatus("Approved"); + }else if(company.getStatus() == 2){ + reg.setStatus("Rejected"); + } + + if(company.isActive()){ + reg.setCompanyStatus("Active"); + }else{ + reg.setCompanyStatus("Blacklisted"); + } return reg; } @@ -143,6 +183,48 @@ public void rejectCompanyRegistration(int id, int rejectedBy) { } } + @Override + public boolean blacklistCompany(int id, int rejectedBy) { + Company company = companyDAO.findOne(id); + + if (company == null) { + throw new ApplicationException("Company Registration not found"); + }else{ + company.setActive(false); + company.setLastUpdatedBy(rejectedBy); + company.setLastUpdatedDate(new Date()); + + companyDAO.save(company); + + // Send email notification to blacklisted company + Set adminEmails = userRoleService.findCompanyAdminEmails(company.getId()); + if (adminEmails != null && adminEmails.size()> 0) { + Map params = new HashMap<>(); + params.put(TTConstants.PARAM_COMPANY, company); + params.put(TTConstants.PARAM_EMAILS, adminEmails.toArray(new String[adminEmails.size()])); + notificationService.sendNotification(NotificationServiceImpl.NOTI_MODE.company_blacklisted_noti, params); + } + + return true; + } + } + + @Override + public boolean unblacklistCompany(int id, int rejectedBy) { + Company company = companyDAO.findOne(id); + + if (company == null) { + throw new ApplicationException("Company Registration not found"); + }else{ + company.setActive(true); + company.setLastUpdatedBy(rejectedBy); + company.setLastUpdatedDate(new Date()); + + companyDAO.save(company); + return true; + } + } + @Override public Company findById(int id) { return companyDAO.findOne(id); diff --git a/src/main/java/com/chlorocode/tendertracker/service/CorrigendumService.java b/src/main/java/com/chlorocode/tendertracker/service/CorrigendumService.java index 47f6b67..6d840c4 100644 --- a/src/main/java/com/chlorocode/tendertracker/service/CorrigendumService.java +++ b/src/main/java/com/chlorocode/tendertracker/service/CorrigendumService.java @@ -6,13 +6,65 @@ import java.util.List; +/** + * Service interface for corrigendum + */ public interface CorrigendumService { + /** + * This method is used to find corrigendum by id. + * + * @param corrigendumId unique identifier of the corrigendum + * @return Corrigendum + */ Corrigendum findCorrigendumById(int corrigendumId); + + /** + * This method is used to find all corrigendums for a particular tender. + * + * @param tenderId unique identifier of the tender + * @return list of corrigendum + */ List findTenderCorrigendum(int tenderId); + + /** + * This method is used to add new corrigendum. + * + * @param corrigendum corrigendum object to be added + * @param attachments list of files to be attached with the corrigendum + * @return Corrigendum + */ Corrigendum addCorrigendum(Corrigendum corrigendum, List attachments); + + /** + * This method is used to update a corrigendum. + * + * @param corrigendum corrigendum object to be uodated + * @return Corrigendum + */ Corrigendum updateCorrigendum(Corrigendum corrigendum); + + /** + * This method is used to remove a corrigendum. + * + * @param corrigendumId unique identifier of the corrigendum + */ void removeCorrigendum(int corrigendumId); + + /** + * This method is used to add a new document to a corrigendum. + * + * @param attachment attachment to be added + * @param corrigendum corrigendum object + * @param createdBy user who add the document + * @return CorrigendumDocument + */ CorrigendumDocument addCorrigendumDocument(MultipartFile attachment, Corrigendum corrigendum, int createdBy); + + /** + * This method is used to remove document form a corrigendum. + * + * @param id unique identifier of the document + */ void removeCorrigendumDocument(int id); } diff --git a/src/main/java/com/chlorocode/tendertracker/service/CorrigendumServiceImpl.java b/src/main/java/com/chlorocode/tendertracker/service/CorrigendumServiceImpl.java index fd0b997..5b76f0c 100644 --- a/src/main/java/com/chlorocode/tendertracker/service/CorrigendumServiceImpl.java +++ b/src/main/java/com/chlorocode/tendertracker/service/CorrigendumServiceImpl.java @@ -3,10 +3,8 @@ import com.chlorocode.tendertracker.constants.TTConstants; import com.chlorocode.tendertracker.dao.CorrigendumDAO; import com.chlorocode.tendertracker.dao.CorrigendumDocumentDAO; -import com.chlorocode.tendertracker.dao.DocumentDAO; import com.chlorocode.tendertracker.dao.entity.Corrigendum; import com.chlorocode.tendertracker.dao.entity.CorrigendumDocument; -import com.chlorocode.tendertracker.dao.entity.Document; import com.chlorocode.tendertracker.exception.ApplicationException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -17,23 +15,32 @@ import java.util.Date; import java.util.List; +/** + * Service implementation of CorrigendumService + */ @Service public class CorrigendumServiceImpl implements CorrigendumService { private CorrigendumDAO corrigendumDAO; private CorrigendumDocumentDAO corrigendumDocumentDAO; - private DocumentDAO documentDAO; private S3Wrapper s3Wrapper; - private TenderService tenderService; - + private TenderSubscriptionService tenderSubscriptionService; + + /** + * Constructor + * + * @param corrigendumDAO CorrigendumDAO + * @param corrigendumDocumentDAO CorrigendumDocumentDAO + * @param s3Wrapper S3Wrapper + * @param tenderSubscriptionService TenderSubscriptionService + */ @Autowired public CorrigendumServiceImpl(CorrigendumDAO corrigendumDAO, CorrigendumDocumentDAO corrigendumDocumentDAO, - DocumentDAO documentDAO, S3Wrapper s3Wrapper, TenderService tenderService) { + S3Wrapper s3Wrapper, TenderSubscriptionService tenderSubscriptionService) { this.corrigendumDAO = corrigendumDAO; this.corrigendumDocumentDAO = corrigendumDocumentDAO; - this.documentDAO = documentDAO; this.s3Wrapper = s3Wrapper; - this.tenderService = tenderService; + this.tenderSubscriptionService = tenderSubscriptionService; } @Override @@ -62,24 +69,22 @@ public Corrigendum addCorrigendum(Corrigendum corrigendum, List a } // Save to DB - Document doc = new Document(); + CorrigendumDocument doc = new CorrigendumDocument(); doc.setName(f.getOriginalFilename()); doc.setLocation(bucketPath); - doc.setType(3); doc.setCreatedBy(corrigendum.getCreatedBy()); doc.setCreatedDate(new Date()); doc.setLastUpdatedBy(corrigendum.getLastUpdatedBy()); doc.setLastUpdatedDate(new Date()); - documentDAO.save(doc); + doc.setCorrigendum(corrigendum); + corrigendumDocumentDAO.save(doc); - CorrigendumDocument corrigendumDocument = new CorrigendumDocument(); - corrigendumDocument.setDocument(doc); - corrigendum.addDocument(corrigendumDocument); + corrigendum.addDocument(doc); } } if (result != null) { - tenderService.sendBookmarkNoti(result.getTender(), TTConstants.ADD_CORRIGENDUM); + tenderSubscriptionService.sendBookmarkNoti(result.getTender(), TTConstants.ADD_CORRIGENDUM); } return result; @@ -96,15 +101,7 @@ public void removeCorrigendum(int corrigendumId) { Corrigendum corrigendum = corrigendumDAO.findOne(corrigendumId); for (CorrigendumDocument corrigendumDocument : corrigendum.getDocuments()) { - Document doc = corrigendumDocument.getDocument(); - // Remove from S3 - String bucketPath = "tender_corrigendums/" + corrigendum.getId() + "/" + doc.getName(); - s3Wrapper.deleteObject(bucketPath); - - corrigendumDocument.setCorrigendum(null); - corrigendumDocument.setDocument(null); - corrigendumDocumentDAO.delete(corrigendumDocument); - documentDAO.delete(doc); + removeCorrigendumDocument(corrigendumDocument.getId()); } corrigendumDAO.delete(corrigendum); @@ -122,36 +119,27 @@ public CorrigendumDocument addCorrigendumDocument(MultipartFile attachment, Corr } // Save to DB - Document doc = new Document(); + CorrigendumDocument doc = new CorrigendumDocument(); doc.setName(attachment.getOriginalFilename()); doc.setLocation(bucketPath); - doc.setType(3); doc.setCreatedBy(createdBy); doc.setCreatedDate(new Date()); doc.setLastUpdatedBy(createdBy); doc.setLastUpdatedDate(new Date()); - documentDAO.save(doc); - - CorrigendumDocument corrigendumDocument = new CorrigendumDocument(); - corrigendumDocument.setDocument(doc); - corrigendumDocument.setCorrigendum(corrigendum); - - return corrigendumDocumentDAO.save(corrigendumDocument); + doc.setCorrigendum(corrigendum); + return corrigendumDocumentDAO.save(doc); } @Override @Transactional public void removeCorrigendumDocument(int id) { CorrigendumDocument corrigendumDocument = corrigendumDocumentDAO.findOne(id); - Document document = corrigendumDocument.getDocument(); // Remove from S3 - String bucketPath = "tender_corrigendums/" + corrigendumDocument.getCorrigendum().getId() + "/" + document.getName(); + String bucketPath = "tender_corrigendums/" + corrigendumDocument.getCorrigendum().getId() + "/" + corrigendumDocument.getName(); s3Wrapper.deleteObject(bucketPath); corrigendumDocument.setCorrigendum(null); - corrigendumDocument.setDocument(null); corrigendumDocumentDAO.delete(corrigendumDocument); - documentDAO.delete(document); } } diff --git a/src/main/java/com/chlorocode/tendertracker/service/EvaluationService.java b/src/main/java/com/chlorocode/tendertracker/service/EvaluationService.java index f825021..77c84ca 100644 --- a/src/main/java/com/chlorocode/tendertracker/service/EvaluationService.java +++ b/src/main/java/com/chlorocode/tendertracker/service/EvaluationService.java @@ -1,16 +1,66 @@ package com.chlorocode.tendertracker.service; import com.chlorocode.tendertracker.dao.entity.EvaluationCriteria; +import com.chlorocode.tendertracker.dao.entity.EvaluationResult; import java.util.List; /** - * Created by andy on 3/8/2017. + * Service interface for tender evaluation. */ public interface EvaluationService { + /** + * This method is used to find all evaluation criteria for a particular tender. + * + * @param tenderId unique identifier of the tender + * @return list of EvaluationCriteria + */ List findEvaluationCriteriaByTender(int tenderId); - EvaluationCriteria create(EvaluationCriteria svc); + + /** + * This method is used to create new evaluation criteria. + * + * @param evaluationCriteria evaluation criteria to be created + * @return Evaluation Criteria + */ + EvaluationCriteria create(EvaluationCriteria evaluationCriteria); + + /** + * This method is used to find evaluation criteria by id. + * + * @param id unique identifier of the evaluation criteria + * @return EvaluationCriteria + */ EvaluationCriteria findCriteriaById(int id); - EvaluationCriteria update(EvaluationCriteria svc); + + /** + * This method is used to update evaluation criteria. + * + * @param evaluationCriteria evaluation criteria to be updated + * @return EvaluationCriteria + */ + EvaluationCriteria update(EvaluationCriteria evaluationCriteria); + + /** + * This method is used to remove evaluation criteria. + * + * @param id unique identifier of the evaluation criteria + */ void removeEvaluationCriteria(int id); + + /** + * This method is used to check if the same user has submitted an tender evaluation for a particular bid before. + * + * @param bidId unique identifier of the bid + * @param userId unique identifier of the user + * @return boolean + */ + boolean isDuplicateEvaluation(int bidId, int userId); + + /** + * This method is used to save tender evaluation result. + * + * @param results list of tender evaluation to be saved + */ + void saveEvaluationResult(List results); } diff --git a/src/main/java/com/chlorocode/tendertracker/service/EvaluationServiceImpl.java b/src/main/java/com/chlorocode/tendertracker/service/EvaluationServiceImpl.java index b50368c..ffab251 100644 --- a/src/main/java/com/chlorocode/tendertracker/service/EvaluationServiceImpl.java +++ b/src/main/java/com/chlorocode/tendertracker/service/EvaluationServiceImpl.java @@ -1,22 +1,34 @@ package com.chlorocode.tendertracker.service; import com.chlorocode.tendertracker.dao.EvaluationCriteriaDAO; +import com.chlorocode.tendertracker.dao.EvaluationResultDAO; import com.chlorocode.tendertracker.dao.entity.EvaluationCriteria; +import com.chlorocode.tendertracker.dao.entity.EvaluationResult; import com.chlorocode.tendertracker.exception.ApplicationException; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; /** - * Created by andy on 3/8/2017. + * Service implementation of EvaluationService */ @Service public class EvaluationServiceImpl implements EvaluationService { private EvaluationCriteriaDAO evaDao; + private EvaluationResultDAO evaResDao; - private EvaluationServiceImpl(EvaluationCriteriaDAO evaDao) + /** + * Constructor + * + * @param evaDao EvaluationCriteriaDAO + * @param evaResDao EvaluationResultDAO + */ + @Autowired + private EvaluationServiceImpl(EvaluationCriteriaDAO evaDao, EvaluationResultDAO evaResDao) { this.evaDao = evaDao; + this.evaResDao = evaResDao; } @Override @@ -24,14 +36,17 @@ public List findEvaluationCriteriaByTender(int tenderId) { return evaDao.findEvaluationCriteriaByTender(tenderId); } + @Override public EvaluationCriteria create(EvaluationCriteria svc){ return evaDao.saveAndFlush(svc); } + @Override public EvaluationCriteria update(EvaluationCriteria svc){ return evaDao.save(svc); } + @Override public EvaluationCriteria findCriteriaById(int id){ return evaDao.findOne(id); } @@ -41,4 +56,19 @@ public void removeEvaluationCriteria(int id) { EvaluationCriteria evaluationCriteria = evaDao.findOne(id); evaDao.delete(evaluationCriteria); } + + @Override + public boolean isDuplicateEvaluation(int bidId, int userId) { + List results = evaResDao.findEvaluationResultByBidAndEvaluator(bidId, userId); + return results.size() > 0; + } + + @Override + public void saveEvaluationResult(List results) { + if (isDuplicateEvaluation(results.get(0).getBid().getId(), results.get(0).getEvaluator().getId())) { + throw new ApplicationException("Evaluator has submitted evaluation result before."); + } + + evaResDao.save(results); + } } diff --git a/src/main/java/com/chlorocode/tendertracker/service/ExternalTenderService.java b/src/main/java/com/chlorocode/tendertracker/service/ExternalTenderService.java new file mode 100644 index 0000000..bfebcff --- /dev/null +++ b/src/main/java/com/chlorocode/tendertracker/service/ExternalTenderService.java @@ -0,0 +1,48 @@ +package com.chlorocode.tendertracker.service; + +import com.chlorocode.tendertracker.dao.dto.TenderSearchDTO; +import com.chlorocode.tendertracker.dao.entity.ExternalTender; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; + +import java.util.List; + +/** + * Service interface for external tender. + */ +public interface ExternalTenderService { + + /** + * This method is used to save external tender passed from tender crawler via API. + * + * @param tenders list of ExternalTender to be saved + * @return String + */ + String createTenderWCList(List tenders); + + /** + * This method is used to get all external tenders. + * + * @param pageable paging criteria + * @return page of ExternalTender + */ + Page listAllByPage(Pageable pageable); + + /** + * This method is used to search external tender. + * + * @param searchDTO search criteria + * @param pageable paging criteria + * @return page of ExternalTender + * @see TenderSearchDTO + */ + Page searchTender(TenderSearchDTO searchDTO, Pageable pageable); + + /** + * This method is used to get an external tender by id. + * + * @param id unique identifier of the external tender + * @return ExternalTender + */ + ExternalTender findByID(int id); +} diff --git a/src/main/java/com/chlorocode/tendertracker/service/ExternalTenderServiceImpl.java b/src/main/java/com/chlorocode/tendertracker/service/ExternalTenderServiceImpl.java new file mode 100644 index 0000000..b2cb4ed --- /dev/null +++ b/src/main/java/com/chlorocode/tendertracker/service/ExternalTenderServiceImpl.java @@ -0,0 +1,120 @@ +package com.chlorocode.tendertracker.service; + +import com.chlorocode.tendertracker.dao.ExternalTenderDAO; +import com.chlorocode.tendertracker.dao.ExternalTenderPagingDAO; +import com.chlorocode.tendertracker.dao.dto.TenderSearchDTO; +import com.chlorocode.tendertracker.dao.entity.ExternalTender; +import com.chlorocode.tendertracker.dao.specs.ExternalTenderSpecs; +import com.chlorocode.tendertracker.logging.TTLogger; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.stereotype.Service; + +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; +import java.util.Date; +import java.util.List; + +/** + * Service implementation of ExternalTenderService + */ +@Service +public class ExternalTenderServiceImpl implements ExternalTenderService { + + private ExternalTenderDAO externalTenderDAO; + private ExternalTenderPagingDAO externalTenderPagingDAO; + + private String className; + + /** + * Constructor. + * + * @param externalTenderDAO ExternalTenderDAO + * @param externalTenderPagingDAO ExternalTenderPagingDAO + */ + @Autowired + public ExternalTenderServiceImpl(ExternalTenderDAO externalTenderDAO, ExternalTenderPagingDAO externalTenderPagingDAO) { + this.externalTenderDAO = externalTenderDAO; + this.externalTenderPagingDAO = externalTenderPagingDAO; + } + + @PostConstruct + public void postConstruct() { + className = this.getClass().getName(); + TTLogger.debug(className, "**** TenderWCServiceImpl postConstruct() ****"); + } + + @PreDestroy + public void preDestroy() { + TTLogger.debug(className, "---- TenderWCServiceImpl preDestroy() ----"); + } + + @Override + public String createTenderWCList(List tenders) { + if (tenders != null) { + for (ExternalTender tender : tenders) { + try { + ExternalTender externalTender = externalTenderDAO.findExistingTender(tender.getReferenceNo(), + tender.getTitle(), tender.getTenderSource(), tender.getCompanyName()); + + if (externalTender == null) { + TTLogger.debug(className, "createTenderWC(TenderWC=%s)", tender); + + tender.setCreatedDate(new Date()); + tender.setLastUpdatedDate(new Date()); + externalTenderDAO.save(tender); + + TTLogger.debug(className, "created TenderWC(TenderWC=%s)", tender); + } else { + TTLogger.debug(className, "updateTenderWC(TenderWC=%s)", tender); + + externalTender.setPublishedDate(tender.getPublishedDate()); + externalTender.setClosingDate(tender.getClosingDate()); + externalTender.setStatus(tender.getStatus()); + externalTender.setTenderURL(tender.getTenderURL()); + externalTender.setLastUpdatedDate(new Date()); + + externalTenderDAO.save(externalTender); + + TTLogger.debug(className, "updated TenderWC(TenderWC=%s)", tender); + } + } catch (Exception e) { + TTLogger.error(className, "Error while createTenderWC(tenderWC=" + tender.toString(), e); + } + } + } + return "success"; + } + + @Override + public Page listAllByPage(Pageable pageable) { + Specification searchSpec = ExternalTenderSpecs.getAllOpenTender(); + return externalTenderPagingDAO.findAll(searchSpec, pageable); + } + + @Override + public Page searchTender(TenderSearchDTO searchDTO, Pageable pageable) { + Specification searchSpec = null; + if (searchDTO.getSearchText() != null && !searchDTO.getSearchText().trim().isEmpty()) { + searchSpec = ExternalTenderSpecs.byTenderSearchString(searchDTO.getSearchText().trim()); + searchDTO.setCompanyName(null); + searchDTO.setTitle(null); + searchDTO.setRefNo(null); + searchDTO.setEtStatus(null); + } else { + searchSpec = ExternalTenderSpecs.byTenderSearchCriteria( + searchDTO.getTitle() == null ? null : searchDTO.getTitle().trim() + , searchDTO.getCompanyName() == null ? null : searchDTO.getCompanyName().trim() + , searchDTO.getEtStatus(), searchDTO.getTenderSource(), searchDTO.getRefNo()); + searchDTO.setSearchText(null); + } + return externalTenderPagingDAO.findAll(searchSpec, pageable); + } + + @Override + public ExternalTender findByID(int id) { + return externalTenderDAO.findOne((long)id); + } +} diff --git a/src/main/java/com/chlorocode/tendertracker/service/IPGeoLocationService.java b/src/main/java/com/chlorocode/tendertracker/service/IPGeoLocationService.java new file mode 100644 index 0000000..3ec9a8e --- /dev/null +++ b/src/main/java/com/chlorocode/tendertracker/service/IPGeoLocationService.java @@ -0,0 +1,19 @@ +package com.chlorocode.tendertracker.service; + +import com.chlorocode.tendertracker.dao.entity.TenderVisit; + +/** + * Service interface for IP Geo Location. + * This service will get geographical information for a IP address. + */ +public interface IPGeoLocationService { + + /** + * This method will get tender visit information based on IP address. + * + * @param ip ip address + * @return TenderVisit + * @see TenderVisit + */ + TenderVisit getIPDetails(String ip); +} diff --git a/src/main/java/com/chlorocode/tendertracker/service/IPGeoLocationServiceImpl.java b/src/main/java/com/chlorocode/tendertracker/service/IPGeoLocationServiceImpl.java new file mode 100644 index 0000000..5b93029 --- /dev/null +++ b/src/main/java/com/chlorocode/tendertracker/service/IPGeoLocationServiceImpl.java @@ -0,0 +1,80 @@ +package com.chlorocode.tendertracker.service; + +import com.chlorocode.tendertracker.dao.entity.TenderVisit; +import com.chlorocode.tendertracker.logging.TTLogger; +import org.json.JSONObject; +import org.springframework.stereotype.Service; + +import java.io.*; +import java.net.URL; +import java.net.URLConnection; +import java.nio.charset.Charset; +import java.util.Date; + +/** + * Service implementation of IPGeoLocationService using ip-api.com service. + */ +@Service +public class IPGeoLocationServiceImpl implements IPGeoLocationService { + + public static final String SERVICE_URL = "http://ip-api.com/json/"; + public static final int TIMEOUT = 5000; + private String className; + + /** + * Constructor. + */ + public IPGeoLocationServiceImpl() { + this.className = this.getClass().getName(); + } + + @Override + public TenderVisit getIPDetails(String ip) { + try { + URL url = new URL(SERVICE_URL + ip.trim() + "?fields=126975"); + URLConnection con = url.openConnection(); + con.setConnectTimeout(TIMEOUT); + con.setReadTimeout(TIMEOUT); + InputStream is = con.getInputStream(); + BufferedReader rd = new BufferedReader(new InputStreamReader(is, Charset.forName("UTF-8"))); + String jsonText = readAll(rd); + JSONObject json = new JSONObject(jsonText); + + if (json.getString("status").equals("success")) { + TenderVisit visit = new TenderVisit(); + visit.setIpAddress(ip); + visit.setVisitDate(new Date()); + visit.setCountry(json.getString("country")); + visit.setCountryCode(json.getString("countryCode")); + visit.setRegion(json.getString("region")); + visit.setRegionName(json.getString("regionName")); + visit.setCity(json.getString("city")); + visit.setZip(json.getString("zip")); + visit.setLat(json.getDouble("lat")); + visit.setLon(json.getDouble("lon")); + visit.setTimeZone(json.getString("timezone")); + visit.setIsp(json.getString("isp")); + visit.setOrg(json.getString("org")); + visit.setAs(json.getString("as")); + visit.setMobile(json.getBoolean("mobile")); + + return visit; + } else { + return null; + } + + } catch (Exception e) { + TTLogger.error(className, "Error getting IP Geo details", e); + return null; + } + } + + private String readAll(Reader rd) throws IOException { + StringBuilder sb = new StringBuilder(); + int cp; + while ((cp = rd.read()) != -1) { + sb.append((char) cp); + } + return sb.toString(); + } +} diff --git a/src/main/java/com/chlorocode/tendertracker/service/LoginAttemptService.java b/src/main/java/com/chlorocode/tendertracker/service/LoginAttemptService.java index ba07cc6..3b4a609 100644 --- a/src/main/java/com/chlorocode/tendertracker/service/LoginAttemptService.java +++ b/src/main/java/com/chlorocode/tendertracker/service/LoginAttemptService.java @@ -3,27 +3,35 @@ import com.chlorocode.tendertracker.constants.TTConstants; import com.chlorocode.tendertracker.dao.UserDAO; import com.chlorocode.tendertracker.dao.entity.User; -import com.chlorocode.tendertracker.service.notification.NotificationService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.Date; import java.util.Optional; +/** + * Service class to track login attempt. + */ @Service public class LoginAttemptService { private UserDAO userDAO; - private String className; - @Autowired - private NotificationService notificationService; + /** + * Constructor. + * + * @param userDAO UserDAO + */ @Autowired public LoginAttemptService(UserDAO userDAO) { this.userDAO = userDAO; - this.className = this.getClass().getName(); } + /** + * This method is to reset fail count once login is successful. + * + * @param key user email + */ public void loginSucceeded(String key) { Optional u = userDAO.findOneByEmail(key); if (u.isPresent()) { @@ -37,6 +45,11 @@ public void loginSucceeded(String key) { } } + /** + * This method is used to increment fail count once login is failed. + * + * @param key user email + */ public void loginFailed(String key) { Optional u = userDAO.findOneByEmail(key); if (u.isPresent()) { diff --git a/src/main/java/com/chlorocode/tendertracker/service/MilestoneService.java b/src/main/java/com/chlorocode/tendertracker/service/MilestoneService.java new file mode 100644 index 0000000..b87d7a1 --- /dev/null +++ b/src/main/java/com/chlorocode/tendertracker/service/MilestoneService.java @@ -0,0 +1,54 @@ +package com.chlorocode.tendertracker.service; + +import com.chlorocode.tendertracker.dao.entity.Milestone; + +import java.util.List; + +/** + * Service interface for tender milestone. + */ +public interface MilestoneService { + /** + * This method is used to find all milestones for a particular tender. + * + * @param tenderId unique identifier of the tender + * @return list of Milestone + */ + List findMilestoneByTender(int tenderId); + + /** + * This method is used to create new milestone. + * + * @param milestone milestone object to be created + * @return Milestone + */ + Milestone create(Milestone milestone); + + /** + * This method is used to find milestone by id. + * + * @param id unique identifier of the milestone + * @return Milestone + */ + Milestone findMilestoneById(int id); + + /** + * This method is used to update milestone. + * + * @param milestone milestone object to be updated + * @return Milestone + */ + Milestone update(Milestone milestone); + + /** + * This method is used to remove milestone. + * + * @param id unique identifier of the milestone + */ + void removeMilestone(int id); + + /** + * This method is used to send email notification to company administrator when milestone is approaching. + */ + void notifyApproachMilestone(); +} diff --git a/src/main/java/com/chlorocode/tendertracker/service/MilestoneServiceImpl.java b/src/main/java/com/chlorocode/tendertracker/service/MilestoneServiceImpl.java new file mode 100644 index 0000000..c045251 --- /dev/null +++ b/src/main/java/com/chlorocode/tendertracker/service/MilestoneServiceImpl.java @@ -0,0 +1,97 @@ +package com.chlorocode.tendertracker.service; + +import com.chlorocode.tendertracker.constants.TTConstants; +import com.chlorocode.tendertracker.dao.MilestoneDAO; +import com.chlorocode.tendertracker.dao.entity.Milestone; +import com.chlorocode.tendertracker.service.notification.NotificationService; +import com.chlorocode.tendertracker.service.notification.NotificationServiceImpl; +import com.chlorocode.tendertracker.utils.DateUtility; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * Service implementation of MilestoneService. + */ +@Service +public class MilestoneServiceImpl implements MilestoneService { + private MilestoneDAO milestoneDAO; + private UserRoleService userRoleService; + private NotificationService notificationService; + private CodeValueService codeValueService; + + /** + * Constructor + * + * @param milestoneDAO MilestoneDAO + * @param notificationService NotificationService + * @param codeValueService CodeValueService + * @param userRoleService UserRoleService + */ + @Autowired + public MilestoneServiceImpl(MilestoneDAO milestoneDAO, NotificationService notificationService, + CodeValueService codeValueService, UserRoleService userRoleService) + { + this.milestoneDAO = milestoneDAO; + this.notificationService = notificationService; + this.codeValueService = codeValueService; + this.userRoleService = userRoleService; + } + + @Override + public List findMilestoneByTender(int tenderId) { + return milestoneDAO.findMilestoneByTender(tenderId); + } + + @Override + public Milestone create(Milestone svc){ + return milestoneDAO.saveAndFlush(svc); + } + + @Override + public Milestone update(Milestone svc){ + return milestoneDAO.save(svc); + } + + @Override + public Milestone findMilestoneById(int id){ + return milestoneDAO.findOne(id); + } + + @Override + public void removeMilestone(int id) { + Milestone milestone = milestoneDAO.findOne(id); + if (milestone != null) { + milestoneDAO.delete(milestone); + } + } + + @Override + public void notifyApproachMilestone() { + List approachMilestones = milestoneDAO.findApproachMilestone(DateUtility.getFutureDateTime(0, 3, 0, 0)); + if (approachMilestones != null) { + for (Milestone milestone : approachMilestones) { + // Send notification to company admin. + Set adminEmails = userRoleService.findCompanyAdminEmails(milestone.getTender().getCompany().getId()); + String statusDescription = codeValueService.getDescription("milestone_status", milestone.getStatus()); + if (adminEmails != null && adminEmails.size() > 0) { + Map params = new HashMap<>(); + params.put(TTConstants.PARAM_TENDER_ID, milestone.getTender().getId()); + params.put(TTConstants.PARAM_TENDER_TITLE, milestone.getTender().getTitle()); + params.put(TTConstants.PARAM_MILESTONE_DESCRIPTION, milestone.getDescription()); + params.put(TTConstants.PARAM_MILESTONE_DUE_DATE, milestone.getDueDate().toString()); + params.put(TTConstants.PARAM_MILESTONE_STATUS, statusDescription); + params.put(TTConstants.PARAM_EMAILS, adminEmails.toArray(new String[adminEmails.size()])); + notificationService.sendNotification(NotificationServiceImpl.NOTI_MODE.milestone_approach_noti, params); + } + // Update notifyStatus in milestone. + milestone.setNotifyStatus(1); + update(milestone); + } + } + } +} diff --git a/src/main/java/com/chlorocode/tendertracker/service/ProductClarificationService.java b/src/main/java/com/chlorocode/tendertracker/service/ProductClarificationService.java new file mode 100644 index 0000000..41e3943 --- /dev/null +++ b/src/main/java/com/chlorocode/tendertracker/service/ProductClarificationService.java @@ -0,0 +1,44 @@ +package com.chlorocode.tendertracker.service; + +import com.chlorocode.tendertracker.dao.entity.ProductClarification; + +import java.util.List; + +/** + * Service interface for product clarification. + */ +public interface ProductClarificationService { + + /** + * This method is used to get a product clarification by id. + * + * @param id unique identifier of the product clarification + * @return ProductClarification + */ + ProductClarification findById(int id); + + /** + * This method is used to save new product clarification. + * + * @param product product clarification object to be saved + * @return ProductClarification + */ + ProductClarification create(ProductClarification product); + + /** + * This method is used to find all clarifications for a particular product. + * + * @param prodId unique identifier of the product + * @return list of ProductClarification + */ + List findClarificationByProdId(int prodId); + + /** + * This method is used to update product clarification response. + * + * @param id unique identifier of the product clarification + * @param response clarification response + * @return ProductClarification + */ + ProductClarification updateResponse(int id, String response); +} diff --git a/src/main/java/com/chlorocode/tendertracker/service/ProductClarificationServiceImpl.java b/src/main/java/com/chlorocode/tendertracker/service/ProductClarificationServiceImpl.java new file mode 100644 index 0000000..104bb41 --- /dev/null +++ b/src/main/java/com/chlorocode/tendertracker/service/ProductClarificationServiceImpl.java @@ -0,0 +1,70 @@ +package com.chlorocode.tendertracker.service; + +import com.chlorocode.tendertracker.dao.ProductClarificationDAO; +import com.chlorocode.tendertracker.dao.entity.CurrentUser; +import com.chlorocode.tendertracker.dao.entity.ProductClarification; +import com.chlorocode.tendertracker.logging.TTLogger; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Service; + +import java.util.Date; +import java.util.List; + +/** + * Service implementation of ProductClarificationService + */ +@Service +public class ProductClarificationServiceImpl implements ProductClarificationService { + + ProductClarificationDAO dao; + private String className; + + /** + * Constructor. + * + * @param dao ProductClarificationDAO + */ + @Autowired + public ProductClarificationServiceImpl(ProductClarificationDAO dao){ + this.className = this.getClass().getName(); + this.dao = dao; + } + + @Override + public ProductClarification findById(int id) { + return dao.findOne(id); + } + + @Override + public ProductClarification create(ProductClarification product) { + return dao.save(product); + } + + @Override + public List findClarificationByProdId(int prodId) { + return dao.findClarificationByProdId(prodId); + } + + @Override + public ProductClarification updateResponse(int id, String response) { + try{ + ProductClarification dbOjb = dao.findOne(id); + + if(dbOjb == null){ + TTLogger.error(className, "tender clarification not found.ID " + id); + return null; + } + + CurrentUser usr = (CurrentUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); + dbOjb.setResponse(response); + dbOjb.setLastUpdatedDate(new Date()); + dbOjb.setLastUpdatedBy(usr.getUser().getId()); + return dao.save(dbOjb); + + }catch(Exception ex){ + TTLogger.error(className, "error: " , ex); + } + return null; + } +} diff --git a/src/main/java/com/chlorocode/tendertracker/service/ProductService.java b/src/main/java/com/chlorocode/tendertracker/service/ProductService.java new file mode 100644 index 0000000..aebd419 --- /dev/null +++ b/src/main/java/com/chlorocode/tendertracker/service/ProductService.java @@ -0,0 +1,62 @@ +package com.chlorocode.tendertracker.service; + +import com.chlorocode.tendertracker.dao.dto.ProductSearchDTO; +import com.chlorocode.tendertracker.dao.entity.Product; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; + +/** + * Service interface for marketplace product. + */ +public interface ProductService { + + /** + * This method is used to create new product. + * + * @param product product object to be created + * @return Product + */ + Product createProduct(Product product); + + /** + * This method is used to update product. + * + * @param product product object to be updated + * @return Product + */ + Product updateProduct(Product product); + + /** + * This method is used to get all products with paging feature. + * + * @param pageable Pageable + * @return page of product + */ + Page listAllByPage(Pageable pageable); + + /** + * This method is used to find a product by id. + * + * @param id unique identifier of the product + * @return Product + */ + Product findById(int id); + + /** + * This method is used to search product based on search criteria. + * + * @param productSearchDTO DTO containing the search criteria + * @param pageable Pageable + * @return page of product + * @see ProductSearchDTO + */ + Page searchProduct(ProductSearchDTO productSearchDTO, Pageable pageable); + + /** + * This method is used to blacklist a product. + * + * @param productCode unique identifier of the product + * @return Product + */ + Product blacklistProduct(int productCode); +} diff --git a/src/main/java/com/chlorocode/tendertracker/service/ProductServiceImpl.java b/src/main/java/com/chlorocode/tendertracker/service/ProductServiceImpl.java new file mode 100644 index 0000000..967f3e2 --- /dev/null +++ b/src/main/java/com/chlorocode/tendertracker/service/ProductServiceImpl.java @@ -0,0 +1,90 @@ +package com.chlorocode.tendertracker.service; + +import com.chlorocode.tendertracker.dao.ProductDAO; +import com.chlorocode.tendertracker.dao.ProductPagingDAO; +import com.chlorocode.tendertracker.dao.dto.ProductSearchDTO; +import com.chlorocode.tendertracker.dao.entity.CurrentUser; +import com.chlorocode.tendertracker.dao.entity.Product; +import com.chlorocode.tendertracker.dao.specs.ProductSpecs; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Date; + +/** + * Service implementation of ProductService. + */ +@Service +public class ProductServiceImpl implements ProductService { + + private ProductDAO productDAO; + private ProductPagingDAO productPagingDAO; + + /** + * Constructor. + * + * @param productDAO ProductDAO + * @param productPagingDAO ProductPagingDAO + */ + @Autowired + public ProductServiceImpl(ProductDAO productDAO, ProductPagingDAO productPagingDAO) { + this.productDAO = productDAO; + this.productPagingDAO = productPagingDAO; + } + + @Override + @Transactional + public Product createProduct(Product product) { + return productDAO.save(product); + } + + @Override + public Product updateProduct(Product product) { + return productDAO.save(product); + } + + @Override + public Page listAllByPage(Pageable pageable) { + Specification specification = ProductSpecs.getAll(); + return productPagingDAO.findAll(specification, pageable); + } + + @Override + public Page searchProduct(ProductSearchDTO productSearchDTO, Pageable pageable) { + Specification specification; + + if (productSearchDTO.getSearchText() != null + && !productSearchDTO.getSearchText().trim().isEmpty()) { + specification = ProductSpecs.byProductSearchString(productSearchDTO.getSearchText().trim()); + productSearchDTO.setCompanyName(null); + productSearchDTO.setTitle(null); + } else { + specification = ProductSpecs.byProductSearchCriteria( + productSearchDTO.getTitle() == null ? null : productSearchDTO.getTitle().trim() + , productSearchDTO.getCompanyName() == null ? null : productSearchDTO.getCompanyName().trim()); + productSearchDTO.setSearchText(null); + } + + return productPagingDAO.findAll(specification, pageable); + } + + @Override + public Product blacklistProduct(int productCode) { + Product p = productDAO.findOne(productCode); + p.setStatus(1); + p.setLastUpdatedDate(new Date()); + CurrentUser usr = (CurrentUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); + p.setLastUpdatedBy(usr.getId()); + return productDAO.save(p); + } + + @Override + public Product findById(int id) { + return productDAO.findOne(id); + } +} diff --git a/src/main/java/com/chlorocode/tendertracker/service/ReportService.java b/src/main/java/com/chlorocode/tendertracker/service/ReportService.java new file mode 100644 index 0000000..b3c594b --- /dev/null +++ b/src/main/java/com/chlorocode/tendertracker/service/ReportService.java @@ -0,0 +1,72 @@ +package com.chlorocode.tendertracker.service; + +import com.chlorocode.tendertracker.dao.dto.ProcurementReportDTO; +import com.chlorocode.tendertracker.dao.dto.ReportSummaryDTO; + +import java.util.Date; +import java.util.List; + +/** + * Service interface for report. + */ +public interface ReportService { + /** + * This method is used to retrieve tender report data based on date range. + * + * @param openDateFrom opening date from + * @param openDateTo opening date to + * @param closeDateFrom closing date from + * @param closeDateTo closing date to + * @param category tender category + * @param status tender status + * @return list of report data + * @see ProcurementReportDTO + */ + List findAllByDateRange(Date openDateFrom, Date openDateTo, + Date closeDateFrom, Date closeDateTo, + String category, String status); + + /** + * This method is used to get tender summary report data. + * + * @param startDate from date + * @param endDate to date + * @return list of report data + * @see ReportSummaryDTO + */ + List findTenderSummary(Date startDate, Date endDate); + + /** + * This method is used to get company summary report data. + * + * @param startDate from date + * @param endDate to date + * @return list of report data + * @see ReportSummaryDTO + */ + List findCompanySummary(Date startDate, Date endDate); + + /** + * This method is used to get number of visitors for a particular tender. + * + * @param tenderId unique identifier of the tender. + * @return integer + */ + Integer getNumberOfVisit(int tenderId); + + /** + * This method is used to get number of unique visitors for a particular tender. + * + * @param tenderId unique identifier of the tender. + * @return integer + */ + Integer getNumberOfUniqueVisit(int tenderId); + + /** + * This method is used to get the top country visitors for a particular tender. + * + * @param tenderId unique identifier of the tender. + * @return integer + */ + List getTopCountryVisitor(int tenderId); +} diff --git a/src/main/java/com/chlorocode/tendertracker/service/ReportServiceImpl.java b/src/main/java/com/chlorocode/tendertracker/service/ReportServiceImpl.java new file mode 100644 index 0000000..48a54ac --- /dev/null +++ b/src/main/java/com/chlorocode/tendertracker/service/ReportServiceImpl.java @@ -0,0 +1,93 @@ +package com.chlorocode.tendertracker.service; + +import com.chlorocode.tendertracker.dao.CompanyDAO; +import com.chlorocode.tendertracker.dao.TenderDAO; +import com.chlorocode.tendertracker.dao.dto.ProcurementReportDTO; +import com.chlorocode.tendertracker.dao.dto.ReportSummaryDTO; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.PageRequest; +import org.springframework.stereotype.Service; + +import java.math.BigInteger; +import java.util.Date; +import java.util.LinkedList; +import java.util.List; + +/** + * Service implementation of ReportService. + */ +@Service +public class ReportServiceImpl implements ReportService { + + private TenderDAO tenderDAO; + private CompanyDAO companyDAO; + + /** + * Constructor. + * + * @param tenderDAO TenderDAO + * @param companyDAO CompanyDAO + */ + @Autowired + public ReportServiceImpl(TenderDAO tenderDAO, CompanyDAO companyDAO) { + this.tenderDAO = tenderDAO; + this.companyDAO = companyDAO; + } + + @Override + public List findAllByDateRange(Date openDateFrom, Date openDateTo, + Date closeDateFrom, Date closeDateTo, + String category, String status) { + + List results = new LinkedList(); + + List rawResult = tenderDAO.findAllByDateRange(openDateFrom, openDateTo, closeDateFrom, closeDateTo, + category, status); + for (Object[] rows : rawResult) { + ProcurementReportDTO row = new ProcurementReportDTO((String)rows[0], (String)rows[1], (String)rows[2], + (String)rows[3], (Date)rows[4], (Date)rows[5], (String)rows[6]); + results.add(row); + } + + return results; + } + + @Override + public List findTenderSummary(Date startDate, Date endDate) { + List rawResult = tenderDAO.getTenderSummary(startDate, endDate); + List results = new LinkedList(); + + for (Object[] rows : rawResult) { + ReportSummaryDTO row = new ReportSummaryDTO((String)rows[0], (String.valueOf((BigInteger)rows[1]))); + results.add(row); + } + return results; + } + + @Override + public List findCompanySummary(Date startDate, Date endDate) { + List rawResult = companyDAO.getCompanySummary(startDate, endDate); + List results = new LinkedList(); + + for (Object[] rows : rawResult) { + ReportSummaryDTO row = new ReportSummaryDTO((String)rows[0], (String.valueOf((BigInteger)rows[1]))); + results.add(row); + } + return results; + } + + @Override + public Integer getNumberOfVisit(int tenderId) { + return tenderDAO.getNumberOfVisit(tenderId); + } + + @Override + public Integer getNumberOfUniqueVisit(int tenderId) { + return tenderDAO.getNumberOfUniqueVisit(tenderId); + } + + @Override + public List getTopCountryVisitor(int tenderId) { + return tenderDAO.getTopCountryVisitor(tenderId, new PageRequest(0, 5)); + } +} diff --git a/src/main/java/com/chlorocode/tendertracker/service/S3Wrapper.java b/src/main/java/com/chlorocode/tendertracker/service/S3Wrapper.java index 9e5a3fd..0ad89a0 100644 --- a/src/main/java/com/chlorocode/tendertracker/service/S3Wrapper.java +++ b/src/main/java/com/chlorocode/tendertracker/service/S3Wrapper.java @@ -24,6 +24,9 @@ import java.util.Arrays; import java.util.List; +/** + * Service class to wrap all interaction with AWS S3. + */ @Service public class S3Wrapper { @@ -37,6 +40,13 @@ private PutObjectResult upload(String filePath, String uploadKey) throws FileNot return upload(new FileInputStream(filePath), uploadKey); } + /** + * This method is used to put an object into S3. + * + * @param inputStream input stream + * @param uploadKey AWS S3 key + * @return PutObjectResult + */ public PutObjectResult upload(InputStream inputStream, String uploadKey) { PutObjectRequest putObjectRequest = new PutObjectRequest(bucket, uploadKey, inputStream, new ObjectMetadata()); @@ -49,6 +59,12 @@ public PutObjectResult upload(InputStream inputStream, String uploadKey) { return putObjectResult; } + /** + * This method is used to put multiple objects into S3. + * + * @param multipartFiles objects to be placed into S3 + * @return list of objects placed in S3 + */ public List upload(MultipartFile[] multipartFiles) { List putObjectResults = new ArrayList<>(); @@ -65,6 +81,13 @@ public List upload(MultipartFile[] multipartFiles) { return putObjectResults; } + /** + * This method is used to download an object based on key. + * + * @param key object key to be downloaded + * @return object in byte array + * @throws IOException if IO exception occured + */ public ResponseEntity download(String key) throws IOException { GetObjectRequest getObjectRequest = new GetObjectRequest(bucket, key); @@ -84,6 +107,11 @@ public ResponseEntity download(String key) throws IOException { return new ResponseEntity<>(bytes, httpHeaders, HttpStatus.OK); } + /** + * This method is used to list all objects inside S3 bucket. + * + * @return list of S3 Object + */ public List list() { ObjectListing objectListing = amazonS3Client.listObjects(new ListObjectsRequest().withBucketName(bucket)); @@ -92,6 +120,12 @@ public List list() { return s3ObjectSummaries; } + /** + * This method is used to get pre signed URL for a particular object in S3 bucket. + * + * @param key object key + * @return URL + */ public URL getPreSignedURL(String key) { java.util.Date expiration = new java.util.Date(); long msec = expiration.getTime(); @@ -106,6 +140,11 @@ public URL getPreSignedURL(String key) { return amazonS3Client.generatePresignedUrl(generatePresignedUrlRequest); } + /** + * This method is used to delte object from S3 bucket. + * + * @param key object key + */ public void deleteObject(String key) { amazonS3Client.deleteObject(new DeleteObjectRequest(bucket, key)); } diff --git a/src/main/java/com/chlorocode/tendertracker/service/TenderAppealService.java b/src/main/java/com/chlorocode/tendertracker/service/TenderAppealService.java new file mode 100644 index 0000000..c1e334e --- /dev/null +++ b/src/main/java/com/chlorocode/tendertracker/service/TenderAppealService.java @@ -0,0 +1,46 @@ +package com.chlorocode.tendertracker.service; + +import com.chlorocode.tendertracker.dao.entity.TenderAppeal; + +import java.util.List; + +/** + * Service interface for tender appeal. + */ +public interface TenderAppealService { + + /** + * This method is used to create TenderAppeal. + * + * @param appeal TenderAppeal object to be created + * @return TenderAppeal + */ + TenderAppeal create(TenderAppeal appeal); + + /** + * This method is used to find TenderAppeal by tenderId and companyId. + * + * @param tenderId unique identifier of the tender + * @param companyId unique identifier of the company + * @return list of TenderAppeal + */ + List findTenderAppealsBy(int tenderId, int companyId); + + /** + * This method is used to find TenderAppeal by id. + * + * @param id unique identifier of the TenderAppeal + * @return TenderAppeal + */ + TenderAppeal findById(int id); + + /** + * This method is used to update tender appeal status. + * + * @param id unique identifier of the TenderAppeal + * @param rejectedBy userId who submit the update request + * @param status TenderAppeal status to be updated + * @return boolean + */ + boolean processTenderAppeal(int id, int rejectedBy, int status); +} diff --git a/src/main/java/com/chlorocode/tendertracker/service/TenderAppealServiceImpl.java b/src/main/java/com/chlorocode/tendertracker/service/TenderAppealServiceImpl.java new file mode 100644 index 0000000..22efe4b --- /dev/null +++ b/src/main/java/com/chlorocode/tendertracker/service/TenderAppealServiceImpl.java @@ -0,0 +1,102 @@ +package com.chlorocode.tendertracker.service; + +import com.chlorocode.tendertracker.constants.TTConstants; +import com.chlorocode.tendertracker.dao.TenderAppealDAO; +import com.chlorocode.tendertracker.dao.entity.TenderAppeal; +import com.chlorocode.tendertracker.exception.ApplicationException; +import com.chlorocode.tendertracker.logging.TTLogger; +import com.chlorocode.tendertracker.service.notification.NotificationService; +import com.chlorocode.tendertracker.service.notification.NotificationServiceImpl; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.*; + +/** + * Service implementation of TenderAppeal service. + */ +@Service +public class TenderAppealServiceImpl implements TenderAppealService { + + private TenderAppealDAO dao; + private NotificationService notificationService; + private UserRoleService userRoleService; + + private String className; + + @Autowired + public TenderAppealServiceImpl(TenderAppealDAO dao, NotificationService notificationService, UserRoleService userRoleService) { + this.className = this.getClass().getName(); + this.dao = dao; + this.notificationService = notificationService; + this.userRoleService = userRoleService; + } + + @Override + public TenderAppeal create(TenderAppeal appeal) { + // Validate duplicate submission + List existingAppeals = dao.findTenderAppealsBy(appeal.getTender().getId(), appeal.getCompany().getId()); + if (existingAppeals != null && existingAppeals.size() > 0) { + TTLogger.error(className, "Duplicate appeal detected"); + throw new ApplicationException("Not allowed to submit duplicate appeal."); + } + + try { + appeal = dao.saveAndFlush(appeal); + // Send the email notification to party who submit the tender appeal + if (appeal != null) { + Set adminEmails = userRoleService.findCompanyAdminEmails(appeal.getCompany().getId()); + if (adminEmails != null && adminEmails.size()> 0) { + Map params = new HashMap<>(); + params.put(TTConstants.PARAM_TENDER_ID, appeal.getTender().getId()); + params.put(TTConstants.PARAM_TENDER_TITLE, appeal.getTender().getTitle()); + params.put(TTConstants.PARAM_APPEAL_COMPANY, appeal.getCompany().getName()); + params.put(TTConstants.PARAM_EMAILS, adminEmails.toArray(new String[adminEmails.size()])); + notificationService.sendNotification(NotificationServiceImpl.NOTI_MODE.appeal_create_noti, params); + } + } + return appeal; + } catch (Exception ex) { + TTLogger.error(className, "error: " , ex); + } + + return null; + } + + @Override + public List findTenderAppealsBy(int tenderId, int companyId) { + return dao.findTenderAppealsBy(tenderId,companyId); + } + + @Override + public TenderAppeal findById(int id) { + return dao.findOne(id); + } + + @Override + public boolean processTenderAppeal(int id, int rejectedBy, int status) { + TenderAppeal appeal = dao.findOne(id); + try { + appeal.setStatus(status); + appeal.setLastUpdatedBy(rejectedBy); + appeal.setLastUpdatedDate(new Date()); + dao.saveAndFlush(appeal); + //Send email notification to appealer. if status is 1, means the tender appeal accepted and process by tenderer preparer, if it is 2, means it is rejected by preparer + Set adminEmails = userRoleService.findCompanyAdminEmails(appeal.getCompany().getId()); + if (adminEmails != null && adminEmails.size()> 0) { + Map params = new HashMap<>(); + params.put(TTConstants.PARAM_TENDER_ID, appeal.getTender().getId()); + params.put(TTConstants.PARAM_TENDER_TITLE, appeal.getTender().getTitle()); + params.put(TTConstants.PARAM_APPEAL_COMPANY, appeal.getCompany().getName()); + params.put(TTConstants.PARAM_APPEAL_ACTION, appeal.getStatus()); + params.put(TTConstants.PARAM_EMAILS, adminEmails.toArray(new String[adminEmails.size()])); + notificationService.sendNotification(NotificationServiceImpl.NOTI_MODE.appeal_update_noti, params); + } + return true; + } catch (Exception ex) { + TTLogger.error(className, "error: " , ex); + } + + return false; + } +} diff --git a/src/main/java/com/chlorocode/tendertracker/service/TenderItemService.java b/src/main/java/com/chlorocode/tendertracker/service/TenderItemService.java new file mode 100644 index 0000000..d695452 --- /dev/null +++ b/src/main/java/com/chlorocode/tendertracker/service/TenderItemService.java @@ -0,0 +1,57 @@ +package com.chlorocode.tendertracker.service; + +import com.chlorocode.tendertracker.dao.entity.TenderItem; + +/** + * Service interface for tender item. + */ +public interface TenderItemService { + + /** + * This method is used to get tender item by id. + * + * @param id unique identifier of the tender item + * @return Tender Item + */ + TenderItem findTenderItemById(int id); + + /** + * This method is used to add tender item. + * + * @param tenderItem tender item to be saved + * @return TenderItem + */ + TenderItem addTenderItem(TenderItem tenderItem); + + /** + * This method is used to update tender item. + * + * @param tenderItem tender item to be updated + * @return TenderItem + */ + TenderItem updateTenderItem(TenderItem tenderItem); + + /** + * This method is used to remove tender item. + * + * @param tenderItemId unique identifier of the tender item + */ + void removeTenderItem(int tenderItemId); + + /** + * This method is used to move up tender item order. + * + * @param tenderItemId unique identifier of the tender item + * @param tenderId unique identifier of the tender + */ + void moveUpTenderItem(int tenderItemId, int tenderId); + + /** + * This method is used to move down tender item order. + * + * @param tenderItemId unique identifier of the tender item + * @param tenderId unique identifier of the tender + */ + void moveDownTenderItem(int tenderItemId, int tenderId); + +} diff --git a/src/main/java/com/chlorocode/tendertracker/service/TenderItemServiceImpl.java b/src/main/java/com/chlorocode/tendertracker/service/TenderItemServiceImpl.java new file mode 100644 index 0000000..ea737f8 --- /dev/null +++ b/src/main/java/com/chlorocode/tendertracker/service/TenderItemServiceImpl.java @@ -0,0 +1,93 @@ +package com.chlorocode.tendertracker.service; + +import com.chlorocode.tendertracker.constants.TTConstants; +import com.chlorocode.tendertracker.dao.TenderItemDAO; +import com.chlorocode.tendertracker.dao.entity.TenderItem; +import com.chlorocode.tendertracker.exception.ApplicationException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import javax.transaction.Transactional; + +/** + * Service implementation of TenderItemService. + */ +@Service +public class TenderItemServiceImpl implements TenderItemService { + + private TenderItemDAO tenderItemDAO; + private TenderSubscriptionService tenderSubscriptionService; + + /** + * Constructor. + * + * @param tenderItemDAO TenderItemDAO + * @param tenderSubscriptionService TenderSubscriptionService + */ + @Autowired + public TenderItemServiceImpl(TenderItemDAO tenderItemDAO, TenderSubscriptionService tenderSubscriptionService) { + this.tenderItemDAO = tenderItemDAO; + this.tenderSubscriptionService=tenderSubscriptionService; + } + + @Override + public TenderItem findTenderItemById(int id) { + return tenderItemDAO.findOne(id); + } + + @Override + public TenderItem addTenderItem(TenderItem tenderItem) { + if (tenderItem.getQuantity() < 0) { + throw new ApplicationException("Tender Item Quantity must be greater than 0"); + } + + return tenderItemDAO.save(tenderItem); + } + + @Override + public TenderItem updateTenderItem(TenderItem tenderItem) { + if (tenderItem.getQuantity() < 0) { + throw new ApplicationException("Tender Item Quantity must be greater than 0"); + } + + tenderItem = tenderItemDAO.save(tenderItem); + tenderSubscriptionService.sendBookmarkNoti(tenderItem.getTender(), TTConstants.UPDATE_TENDER); + + return tenderItem; + } + + @Override + public void removeTenderItem(int tenderItemId) { + tenderItemDAO.delete(tenderItemId); + } + + @Override + @Transactional + public void moveUpTenderItem(int tenderItemId, int tenderId) { + TenderItem tenderItem = tenderItemDAO.findOne(tenderItemId); + int currentOrder = tenderItem.getSort(); + + TenderItem tenderItemReplaced = tenderItemDAO.getTenderItemBySort(tenderId, currentOrder - 1); + + tenderItem.setSort(currentOrder - 1); + tenderItemReplaced.setSort(currentOrder); + + tenderItemDAO.save(tenderItem); + tenderItemDAO.save(tenderItemReplaced); + } + + @Override + @Transactional + public void moveDownTenderItem(int tenderItemId, int tenderId) { + TenderItem tenderItem = tenderItemDAO.findOne(tenderItemId); + int currentOrder = tenderItem.getSort(); + + TenderItem tenderItemReplaced = tenderItemDAO.getTenderItemBySort(tenderId, currentOrder + 1); + + tenderItem.setSort(currentOrder + 1); + tenderItemReplaced.setSort(currentOrder); + + tenderItemDAO.save(tenderItem); + tenderItemDAO.save(tenderItemReplaced); + } +} diff --git a/src/main/java/com/chlorocode/tendertracker/service/TenderService.java b/src/main/java/com/chlorocode/tendertracker/service/TenderService.java index e0aac9e..b97b82a 100644 --- a/src/main/java/com/chlorocode/tendertracker/service/TenderService.java +++ b/src/main/java/com/chlorocode/tendertracker/service/TenderService.java @@ -1,39 +1,99 @@ package com.chlorocode.tendertracker.service; import com.chlorocode.tendertracker.dao.dto.TenderSearchDTO; -import com.chlorocode.tendertracker.dao.entity.*; +import com.chlorocode.tendertracker.dao.entity.Tender; +import com.chlorocode.tendertracker.dao.entity.TenderAward; +import com.chlorocode.tendertracker.dao.entity.TenderDocument; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.web.multipart.MultipartFile; import java.util.List; +/** + * Service interface for tender. + */ public interface TenderService { + /** + * This method is used to find tender by id. + * + * @param id unique identifier of the tender + * @return Tender + */ Tender findById(int id); + + /** + * This method is used to list all tenders. + * + * @return list of tender + */ List findTender(); + + /** + * This method is used to create a new tender. + * + * @param t tender object to be created + * @param attachments tender attachments document + * @return Tender + */ Tender createTender(Tender t, List attachments); - Tender updateTender(Tender tender); - TenderItem findTenderItemById(int id); - TenderItem addTenderItem(TenderItem tenderItem); - TenderItem updateTenderItem(TenderItem tenderItem); - void removeTenderItem(int tenderItemId); + /** + * This method is used to update tender. + * + * @param tender tender object to be updated + * @return Tender + */ + Tender updateTender(Tender tender); + /** + * This method is used to add tender document. + * + * @param attachment document to be attached + * @param tender tender object + * @param createdBy user id who add the document + * @return TenderDocument + */ TenderDocument addTenderDocument(MultipartFile attachment, Tender tender, int createdBy); + + /** + * This method is used to remove tender document. + * + * @param id unique identifier of the tender document + */ void removeTenderDocument(int id); - TenderBookmark findTenderBookmark(int tenderId, int userId); - TenderBookmark bookmarkTender(Tender tender, User user); - void removeTenderBookmark(int tenderId, int userId); + /** + * This method is used to list all tenders with paging. + * + * @param pageable paging criteria + * @return page of Tender + */ + Page listAllByPage(Pageable pageable); - List findUserSubscription(int userId); - void subscribeToTenderCategory(User user, List categories); + /** + * This method is used to search tenders based on search criteria. + * + * @param searchDTO tender search criteria + * @param pageable paging criteria + * @return page of Tender + */ + Page searchTender(TenderSearchDTO searchDTO, Pageable pageable); - List findTenderBookmarkByUserId(int userId); + /** + * This method is used to log tender view statistic information. + * + * @param tender visited tender + * @param ipAddress ip address of the visitor + */ + void logVisit(Tender tender, String ipAddress); - Page listAllByPage(Pageable pageable); - Page searchTender(TenderSearchDTO searchDTO, Pageable pageable); + /** + * This method is used to save a tender award. + * + * @param tenderAward tender award object to be saved + */ + void awardTender(TenderAward tenderAward); - void sendBookmarkNoti(Tender tender, int changeType); } diff --git a/src/main/java/com/chlorocode/tendertracker/service/TenderServiceImpl.java b/src/main/java/com/chlorocode/tendertracker/service/TenderServiceImpl.java index 27bd81f..aeb072b 100644 --- a/src/main/java/com/chlorocode/tendertracker/service/TenderServiceImpl.java +++ b/src/main/java/com/chlorocode/tendertracker/service/TenderServiceImpl.java @@ -12,6 +12,8 @@ import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.domain.Specification; +import org.springframework.scheduling.annotation.Async; +import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; @@ -19,33 +21,66 @@ import java.io.IOException; import java.util.*; +/** + * Service implementation of TenderService. + */ @Service public class TenderServiceImpl implements TenderService { private TenderDAO tenderDAO; - private TenderItemDAO tenderItemDAO; private TenderDocumentDAO tenderDocumentDAO; private TenderCategorySubscriptionDAO tenderCategorySubscriptionDAO; - private DocumentDAO documentDAO; private S3Wrapper s3Wrapper; private TenderBookmarkDAO tenderBookmarkDAO; private TenderPagingDAO tenderPagingDAO; private NotificationService notificationService; - + private IPGeoLocationService ipGeoLocationService; + private TenderVisitDAO tenderVisitDAO; + private TenderAwardDAO tenderAwardDAO; + private UserService userService; + private BidService bidService; + private UserRoleService userRoleService; + private TenderSubscriptionService tenderSubscriptionService; + + /** + * Constructor. + * + * @param tenderDAO TenderDAO + * @param s3Wrapper S3Wrapper + * @param tenderBookmarkDAO TenderBookmarkDAO + * @param tenderDocumentDAO TenderDocumentDAO + * @param tenderCategorySubscriptionDAO TenderCategorySubscriptionDAO + * @param tenderPagingDAO TenderPagingDAO + * @param notificationService NotificationService + * @param ipGeoLocationService IPGeoLocationService + * @param tenderVisitDAO TenderVisitDAO + * @param tenderAwardDAO TenderAwardDAO + * @param userService UserService + * @param bidService BidService + * @param userRoleService UserRoleService + * @param tenderSubscriptionService TenderSubscriptionService + */ @Autowired - public TenderServiceImpl(TenderDAO tenderDAO, DocumentDAO documentDAO, S3Wrapper s3Wrapper, TenderBookmarkDAO tenderBookmarkDAO - , TenderItemDAO tenderItemDAO, TenderDocumentDAO tenderDocumentDAO + public TenderServiceImpl(TenderDAO tenderDAO, S3Wrapper s3Wrapper, TenderBookmarkDAO tenderBookmarkDAO + , TenderDocumentDAO tenderDocumentDAO, TenderSubscriptionService tenderSubscriptionService , TenderCategorySubscriptionDAO tenderCategorySubscriptionDAO, TenderPagingDAO tenderPagingDAO - , NotificationService notificationService) { + , NotificationService notificationService, IPGeoLocationService ipGeoLocationService + , TenderVisitDAO tenderVisitDAO, TenderAwardDAO tenderAwardDAO, UserService userService + , BidService bidService, UserRoleService userRoleService) { this.tenderDAO = tenderDAO; - this.tenderItemDAO = tenderItemDAO; this.tenderDocumentDAO = tenderDocumentDAO; + this.tenderSubscriptionService=tenderSubscriptionService; this.tenderCategorySubscriptionDAO = tenderCategorySubscriptionDAO; - this.documentDAO = documentDAO; this.s3Wrapper = s3Wrapper; this.tenderBookmarkDAO = tenderBookmarkDAO; this.tenderPagingDAO = tenderPagingDAO; this.notificationService = notificationService; + this.ipGeoLocationService = ipGeoLocationService; + this.tenderVisitDAO = tenderVisitDAO; + this.tenderAwardDAO = tenderAwardDAO; + this.userService = userService; + this.bidService = bidService; + this.userRoleService=userRoleService; } @Override @@ -77,6 +112,16 @@ public Tender createTender(Tender t, List attachments) { throw new ApplicationException("At least one Tender Item must be provided"); } + if (t.getTenderType() == 2 && t.getInvitedCompanies().size() == 0) { + throw new ApplicationException("For Closed Tender, please provide at least one company to be invited"); + } + + for (TenderItem ti : t.getItems()) { + if (ti.getQuantity() < 0) { + throw new ApplicationException("Tender Item Quantity must be greater than 0"); + } + } + // Set tender status to OPEN t.setStatus(1); @@ -92,19 +137,15 @@ public Tender createTender(Tender t, List attachments) { } // Save to DB - Document doc = new Document(); + TenderDocument doc = new TenderDocument(); doc.setName(f.getOriginalFilename()); doc.setLocation(bucketPath); - doc.setType(1); doc.setCreatedBy(t.getCreatedBy()); doc.setCreatedDate(new Date()); doc.setLastUpdatedBy(t.getLastUpdatedBy()); doc.setLastUpdatedDate(new Date()); - documentDAO.save(doc); - - TenderDocument tenderDocument = new TenderDocument(); - tenderDocument.setDocument(doc); - t.addTenderDocument(tenderDocument); + t.addTenderDocument(doc); + tenderDocumentDAO.save(doc); } if (result != null) { @@ -148,33 +189,10 @@ public Tender updateTender(Tender tender) { } tender = tenderDAO.save(tender); - sendBookmarkNoti(tender, TTConstants.UPDATE_TENDER); + tenderSubscriptionService.sendBookmarkNoti(tender, TTConstants.UPDATE_TENDER); return tender; } - @Override - public TenderItem findTenderItemById(int id) { - return tenderItemDAO.findOne(id); - } - - @Override - public TenderItem addTenderItem(TenderItem tenderItem) { - return tenderItemDAO.save(tenderItem); - } - - @Override - public TenderItem updateTenderItem(TenderItem tenderItem) { - tenderItem = tenderItemDAO.save(tenderItem); - sendBookmarkNoti(tenderItem.getTender(), TTConstants.UPDATE_TENDER); - - return tenderItem; - } - - @Override - public void removeTenderItem(int tenderItemId) { - tenderItemDAO.delete(tenderItemId); - } - @Override @Transactional public TenderDocument addTenderDocument(MultipartFile attachment, Tender tender, int createdBy) { @@ -187,106 +205,43 @@ public TenderDocument addTenderDocument(MultipartFile attachment, Tender tender, } // Save to DB - Document doc = new Document(); + TenderDocument doc = new TenderDocument(); doc.setName(attachment.getOriginalFilename()); doc.setLocation(bucketPath); - doc.setType(1); doc.setCreatedBy(createdBy); doc.setCreatedDate(new Date()); doc.setLastUpdatedBy(createdBy); doc.setLastUpdatedDate(new Date()); - documentDAO.save(doc); - - TenderDocument tenderDocument = new TenderDocument(); - tenderDocument.setDocument(doc); - tenderDocument.setTender(tender); - - return tenderDocumentDAO.save(tenderDocument); + doc.setTender(tender); + return tenderDocumentDAO.save(doc); } @Override @Transactional public void removeTenderDocument(int id) { TenderDocument tenderDocument = tenderDocumentDAO.findOne(id); - Document document = tenderDocument.getDocument(); // Remove from S3 - String bucketPath = "tender_documents/" + tenderDocument.getTender().getId() + "/" + document.getName(); + String bucketPath = "tender_documents/" + tenderDocument.getTender().getId() + "/" + tenderDocument.getName(); s3Wrapper.deleteObject(bucketPath); tenderDocument.setTender(null); - tenderDocument.setDocument(null); tenderDocumentDAO.delete(tenderDocument); - documentDAO.delete(document); - } - - @Override - public TenderBookmark findTenderBookmark(int tenderId, int userId) { - return tenderBookmarkDAO.findTenderBookmarkByUserAndTender(tenderId, userId); - } - - @Override - public TenderBookmark bookmarkTender(Tender tender, User user) { - TenderBookmark tenderBookmark = new TenderBookmark(); - tenderBookmark.setUser(user); - tenderBookmark.setTender(tender); - tenderBookmark.setCreatedBy(user.getId()); - tenderBookmark.setCreatedDate(new Date()); - tenderBookmark.setLastUpdatedBy(user.getId()); - tenderBookmark.setLastUpdatedDate(new Date()); - - return tenderBookmarkDAO.save(tenderBookmark); - } - - @Override - public void removeTenderBookmark(int tenderId, int userId) { - TenderBookmark tenderBookmark = findTenderBookmark(tenderId, userId); - tenderBookmarkDAO.delete(tenderBookmark); - } - - @Override - public List findUserSubscription(int userId) { - return tenderCategorySubscriptionDAO.findUserSubscription(userId); - } - - @Override - @Transactional - public void subscribeToTenderCategory(User user, List categories) { - tenderCategorySubscriptionDAO.removeExistingSubscription(user.getId()); - - List subsList = new LinkedList<>(); - - for (TenderCategory i : categories) { - TenderCategorySubscription subs = new TenderCategorySubscription(); - subs.setUser(user); - subs.setTenderCategory(i); - subs.setCreatedBy(user.getId()); - subs.setCreatedDate(new Date()); - subs.setLastUpdatedBy(user.getId()); - subs.setLastUpdatedDate(new Date()); - - subsList.add(subs); - } - - tenderCategorySubscriptionDAO.save(subsList); - } - - @Override - public List findTenderBookmarkByUserId(int userId) { - return tenderBookmarkDAO.findTenderBookmarkByUserId(userId); } @Override public Page listAllByPage(Pageable pageable) { - Specification searchSpec = TenderSpecs.getAllOpenTender(); + int companyId = getCompanyId(); + Specification searchSpec = TenderSpecs.getAllOpenTender(companyId, getInviteTenderIds(companyId)); return tenderPagingDAO.findAll(searchSpec, pageable); } @Override public Page searchTender(TenderSearchDTO searchDTO, Pageable pageable) { - Specification searchSpec = null; + int companyId = getCompanyId(); + Specification searchSpec; if (searchDTO.getSearchText() != null && !searchDTO.getSearchText().trim().isEmpty()) { - searchSpec = TenderSpecs.byTenderSearchString(searchDTO.getSearchText().trim()); + searchSpec = TenderSpecs.byTenderSearchString(searchDTO.getSearchText().trim(), companyId, getInviteTenderIds(companyId)); searchDTO.setCompanyName(null); searchDTO.setTitle(null); searchDTO.setRefNo(null); @@ -297,30 +252,88 @@ public Page searchTender(TenderSearchDTO searchDTO, Pageable pageable) { searchDTO.getTitle() == null ? null : searchDTO.getTitle().trim() , searchDTO.getCompanyName() == null ? null : searchDTO.getCompanyName().trim() , searchDTO.getTenderCategory() - , searchDTO.getStatus(), searchDTO.getRefNo()); + , searchDTO.getStatus(), searchDTO.getRefNo() + , companyId, getInviteTenderIds(companyId)); searchDTO.setSearchText(null); } return tenderPagingDAO.findAll(searchSpec, pageable); } @Override - public void sendBookmarkNoti(Tender tender, int changeType) { - if (tender != null) { - // Send tender information to bookmark users. - List tenderBookmarks = tenderBookmarkDAO.findTenderBookmarkByTender(tender.getId()); - if (tenderBookmarks != null) { - Set users = new HashSet<>(); - for (TenderBookmark bookmark : tenderBookmarks) { - if (bookmark.getUser() != null) users.add(bookmark.getUser()); + @Async + public void logVisit(Tender tender, String ipAddress) { + TenderVisit visit = ipGeoLocationService.getIPDetails(ipAddress); + if (visit != null) { + visit.setTender(tender); + tenderVisitDAO.save(visit); + } + } + + @Override + @Transactional + public void awardTender(TenderAward tenderAward) { + tenderAwardDAO.save(tenderAward); + Tender tender = tenderAward.getTender(); + tender.setStatus(3); + tenderDAO.save(tender); + + // Add awarded company user. + Set emails = userRoleService.findCompanyUserEmails(tenderAward.getCompany().getId()); + if (emails == null) { + emails = new HashSet<>(); + } + // Add bid user. + List bids = bidService.findBidByTender(tender.getId()); + if (bids != null) { + for(Bid bid : bids) { + User user = userService.findById(bid.getCreatedBy()); + if (user != null) { + emails.add(user.getEmail()); } - if (users != null && !users.isEmpty()) { - Map params = new HashMap<>(); - params.put(TTConstants.PARAM_TENDER, tender); - params.put(TTConstants.PARAM_EMAILS, users.toArray(new User[users.size()])); - params.put(TTConstants.PARAM_CHANGE_TYPE, changeType); - notificationService.sendNotification(NotificationServiceImpl.NOTI_MODE.tender_bookmark_noti, params); + } + } + // Add bookmark user. + List tenderBookmarks = tenderBookmarkDAO.findTenderBookmarkByTender(tender.getId()); + if (tenderBookmarks != null) { + for (TenderBookmark bookmark : tenderBookmarks) { + if (bookmark.getUser() != null) emails.add(bookmark.getUser().getEmail()); + } + } + + if (emails.size() > 0) { + Map params = new HashMap<>(); + params.put(TTConstants.PARAM_TENDER_ID, tenderAward.getTender().getId()); + params.put(TTConstants.PARAM_TENDER_TITLE, tenderAward.getTender().getTitle()); + params.put(TTConstants.PARAM_COMPANY_NAME, tenderAward.getCompany().getName()); + params.put(TTConstants.PARAM_EMAILS, emails.toArray(new String[emails.size()])); + notificationService.sendNotification(NotificationServiceImpl.NOTI_MODE.tender_award_noti, params); + } + } + + private List getInviteTenderIds(int companyId) { + if (companyId > 0) { + List tenders = tenderDAO.findTenderByInvitedCompany(companyId); + if (tenders != null && tenders.size() > 0) { + List tenderIds = new ArrayList<>(); + for (Tender tender : tenders) { + if (tender != null) { + tenderIds.add(tender.getId()); + } } + return tenderIds; + } + } + return null; + } + + private int getCompanyId() { + Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal(); + if (principal != null && principal instanceof CurrentUser) { + CurrentUser usr = (CurrentUser) principal; + if (usr.getSelectedCompany() != null) { + return usr.getSelectedCompany().getId(); } } + return 0; } } diff --git a/src/main/java/com/chlorocode/tendertracker/service/TenderSubscriptionService.java b/src/main/java/com/chlorocode/tendertracker/service/TenderSubscriptionService.java new file mode 100644 index 0000000..aa7256d --- /dev/null +++ b/src/main/java/com/chlorocode/tendertracker/service/TenderSubscriptionService.java @@ -0,0 +1,76 @@ +package com.chlorocode.tendertracker.service; + +import com.chlorocode.tendertracker.dao.entity.*; + +import java.util.List; + +/** + * Service interface for tender. + */ +public interface TenderSubscriptionService { + + /** + * This method is used to get tender bookmark by tender and user search criteria. + * + * @param tenderId unique identifier of the tender + * @param userId unique identifier of the user + * @return TenderBookmark + */ + TenderBookmark findTenderBookmark(int tenderId, int userId); + + /** + * This method is used to save a tender bookmark. + * + * @param tender tender to be bookmarked + * @param user user who bookmark the tender + * @return TenderBookmark + */ + TenderBookmark bookmarkTender(Tender tender, User user); + + /** + * This method is used to remove a tender bookmark. + * + * @param tenderId unique identifier of the tender + * @param userId unique identifier of the user + */ + void removeTenderBookmark(int tenderId, int userId); + + /** + * This method is used to ge the list of tender category that user subscribe. + * + * @param userId unique identifier of the user + * @return list of TenderCategorySubscription + */ + List findUserSubscription(int userId); + + /** + * This method is used to add tender category subscription. + * + * @param user user who wants to subscribe + * @param categories list of tender category to be subscribed + */ + void subscribeToTenderCategory(User user, List categories); + + /** + * This method is used to find list of tender bookmarks for a particular user. + * + * @param userId unique identifier of the user + * @return list of TenderBookmark + */ + List findTenderBookmarkByUserId(int userId); + + /** + * This method is used to send notification to tender bookmark subscribers. + * + * @param tender tender object where the changes made + * @param changeType type of changes made + */ + void sendBookmarkNoti(Tender tender, int changeType); + + /** + * This method is used by scheduler task to auto close tender status and send notification. + * Tender where the closing date already passed will be automatically updated to closed status and email notification + * will be sent to company administrator. + */ + void autoCloseTenderAndNotify(); +} diff --git a/src/main/java/com/chlorocode/tendertracker/service/TenderSubscriptionServiceImpl.java b/src/main/java/com/chlorocode/tendertracker/service/TenderSubscriptionServiceImpl.java new file mode 100644 index 0000000..bb78f29 --- /dev/null +++ b/src/main/java/com/chlorocode/tendertracker/service/TenderSubscriptionServiceImpl.java @@ -0,0 +1,145 @@ +package com.chlorocode.tendertracker.service; + +import com.chlorocode.tendertracker.constants.TTConstants; +import com.chlorocode.tendertracker.dao.TenderBookmarkDAO; +import com.chlorocode.tendertracker.dao.TenderCategorySubscriptionDAO; +import com.chlorocode.tendertracker.dao.TenderDAO; +import com.chlorocode.tendertracker.dao.entity.*; +import com.chlorocode.tendertracker.service.notification.NotificationService; +import com.chlorocode.tendertracker.service.notification.NotificationServiceImpl; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import javax.transaction.Transactional; +import java.util.*; + +/** + * Service implementation of TenderSubscriptionService. + */ +@Service +public class TenderSubscriptionServiceImpl implements TenderSubscriptionService { + + private TenderDAO tenderDAO; + private TenderCategorySubscriptionDAO tenderCategorySubscriptionDAO; + private TenderBookmarkDAO tenderBookmarkDAO; + private NotificationService notificationService; + private UserRoleService userRoleService; + + /** + * Constructor. + * + * @param tenderDAO TenderDAO + * @param tenderBookmarkDAO TenderBookmarkDAO + * @param tenderCategorySubscriptionDAO TenderCategorySubscriptionDAO + * @param notificationService NotificationService + * @param userRoleService UserRoleService + */ + @Autowired + public TenderSubscriptionServiceImpl(TenderDAO tenderDAO, TenderBookmarkDAO tenderBookmarkDAO + , TenderCategorySubscriptionDAO tenderCategorySubscriptionDAO + , NotificationService notificationService, UserRoleService userRoleService) { + this.tenderDAO = tenderDAO; + this.tenderCategorySubscriptionDAO = tenderCategorySubscriptionDAO; + this.tenderBookmarkDAO = tenderBookmarkDAO; + this.notificationService = notificationService; + this.userRoleService=userRoleService; + } + + @Override + public TenderBookmark findTenderBookmark(int tenderId, int userId) { + return tenderBookmarkDAO.findTenderBookmarkByUserAndTender(tenderId, userId); + } + + @Override + public TenderBookmark bookmarkTender(Tender tender, User user) { + TenderBookmark tenderBookmark = new TenderBookmark(); + tenderBookmark.setUser(user); + tenderBookmark.setTender(tender); + tenderBookmark.setCreatedBy(user.getId()); + tenderBookmark.setCreatedDate(new Date()); + tenderBookmark.setLastUpdatedBy(user.getId()); + tenderBookmark.setLastUpdatedDate(new Date()); + + return tenderBookmarkDAO.save(tenderBookmark); + } + + @Override + public void removeTenderBookmark(int tenderId, int userId) { + TenderBookmark tenderBookmark = findTenderBookmark(tenderId, userId); + tenderBookmarkDAO.delete(tenderBookmark); + } + + @Override + public List findUserSubscription(int userId) { + return tenderCategorySubscriptionDAO.findUserSubscription(userId); + } + + @Override + @Transactional + public void subscribeToTenderCategory(User user, List categories) { + tenderCategorySubscriptionDAO.removeExistingSubscription(user.getId()); + + List subsList = new LinkedList<>(); + + for (TenderCategory i : categories) { + TenderCategorySubscription subs = new TenderCategorySubscription(); + subs.setUser(user); + subs.setTenderCategory(i); + subs.setCreatedBy(user.getId()); + subs.setCreatedDate(new Date()); + subs.setLastUpdatedBy(user.getId()); + subs.setLastUpdatedDate(new Date()); + + subsList.add(subs); + } + + tenderCategorySubscriptionDAO.save(subsList); + } + + @Override + public List findTenderBookmarkByUserId(int userId) { + return tenderBookmarkDAO.findTenderBookmarkByUserId(userId); + } + + @Override + public void sendBookmarkNoti(Tender tender, int changeType) { + if (tender != null) { + // Send tender information to bookmark users. + List tenderBookmarks = tenderBookmarkDAO.findTenderBookmarkByTender(tender.getId()); + if (tenderBookmarks != null) { + Set emails = new HashSet<>(); + for (TenderBookmark bookmark : tenderBookmarks) { + if (bookmark.getUser() != null) emails.add(bookmark.getUser().getEmail()); + } + if (!emails.isEmpty()) { + Map params = new HashMap<>(); + params.put(TTConstants.PARAM_TENDER, tender); + params.put(TTConstants.PARAM_EMAILS, emails.toArray(new String[emails.size()])); + params.put(TTConstants.PARAM_CHANGE_TYPE, changeType); + notificationService.sendNotification(NotificationServiceImpl.NOTI_MODE.tender_bookmark_noti, params); + } + } + } + } + + @Override + public void autoCloseTenderAndNotify() { + //Date currentDateTime = DateUtility.getCurrentDateTime(); + List closingTenders = tenderDAO.findClosingTender(new Date()); + if (closingTenders != null && !closingTenders.isEmpty()) { + for (Tender t : closingTenders) { + // Notify to company administrator. + Set adminEmails = userRoleService.findCompanyAdminEmails(t.getCompany().getId()); + if (adminEmails != null && adminEmails.size()> 0) { + Map params = new HashMap<>(); + params.put(TTConstants.PARAM_TENDER_ID, t.getId()); + params.put(TTConstants.PARAM_TENDER_TITLE, t.getTitle()); + params.put(TTConstants.PARAM_EMAILS, adminEmails.toArray(new String[adminEmails.size()])); + notificationService.sendNotification(NotificationServiceImpl.NOTI_MODE.tender_closed_noti, params); + } + // Change the status of tender to close tender. + tenderDAO.closeTender(t.getId(), new Date()); + } + } + } +} diff --git a/src/main/java/com/chlorocode/tendertracker/service/UenEntityService.java b/src/main/java/com/chlorocode/tendertracker/service/UenEntityService.java index 8602c43..df1fa9d 100644 --- a/src/main/java/com/chlorocode/tendertracker/service/UenEntityService.java +++ b/src/main/java/com/chlorocode/tendertracker/service/UenEntityService.java @@ -3,8 +3,15 @@ import com.chlorocode.tendertracker.dao.entity.UenEntity; /** - * Created by andy on 16/8/2017. + * Service interface for UEN. */ public interface UenEntityService { + + /** + * This method is used to find UEN details. + * + * @param uen uen + * @return UenEntity + */ UenEntity findByUen(String uen); } diff --git a/src/main/java/com/chlorocode/tendertracker/service/UenEntityServiceImpl.java b/src/main/java/com/chlorocode/tendertracker/service/UenEntityServiceImpl.java index ab05efd..1ef14cd 100644 --- a/src/main/java/com/chlorocode/tendertracker/service/UenEntityServiceImpl.java +++ b/src/main/java/com/chlorocode/tendertracker/service/UenEntityServiceImpl.java @@ -6,13 +6,18 @@ import org.springframework.stereotype.Service; /** - * Created by andy on 16/8/2017. + * Service implementation of UenEntityService */ @Service public class UenEntityServiceImpl implements UenEntityService { private UenEntityDAO dao; + /** + * Constructor. + * + * @param dao UenEntityDAO + */ @Autowired public UenEntityServiceImpl(UenEntityDAO dao){ this.dao = dao; diff --git a/src/main/java/com/chlorocode/tendertracker/service/UserRoleService.java b/src/main/java/com/chlorocode/tendertracker/service/UserRoleService.java index 28c3485..95028ac 100644 --- a/src/main/java/com/chlorocode/tendertracker/service/UserRoleService.java +++ b/src/main/java/com/chlorocode/tendertracker/service/UserRoleService.java @@ -6,17 +6,79 @@ import com.chlorocode.tendertracker.dao.entity.UserRole; import java.util.List; +import java.util.Set; /** - * Created by andy on 27/7/2017. + * Service interface for user role. */ public interface UserRoleService { + /** + * This method is used to find role by id. + * + * @param id unique identifier of the role + * @return Role + */ Role findRoleById(int id); + + /** + * This method is used to find user role by id. + * + * @param id unique identifier of the user role + * @return UserRole + */ UserRole findUserRoleById(int id); + + /** + * This method is used to find role that a user has for a particular company. + * + * @param userId unique identifier of the user + * @param companyId unique identifier of the company + * @return list of role + */ List findCompanyUserRole(int userId, int companyId); + /** + * This method is used to add new role for a particular user for a particular company. + * + * @param user user object + * @param roles list of new roles to be added + * @param company company object + * @param createdBy user id who add the new roles + */ void addUserRole(User user, List roles, Company company, int createdBy); + + /** + * This method is used to replace user's existing role to a new list of roles. + * + * @param user user object + * @param roles list of new roles to be added + * @param company company object + * @param updatedBy user id who update the roles + */ void updateUserRole(User user, List roles, Company company, int updatedBy); + + /** + * This method is used to remove user from company. + * + * @param user user object + * @param company company object + */ void removeUserFromCompany(User user, Company company); + + /** + * This method is used to find list of all email addresses of company admin. + * + * @param companyId unique identifier of the company + * @return emails + */ + Set findCompanyAdminEmails(int companyId); + + /** + * This method is used to find list of all email addresses of company user. + * + * @param companyId unique identifier of the company + * @return emails + */ + Set findCompanyUserEmails(int companyId); } diff --git a/src/main/java/com/chlorocode/tendertracker/service/UserRoleServiceImpl.java b/src/main/java/com/chlorocode/tendertracker/service/UserRoleServiceImpl.java index db6ee4f..49c5bc7 100644 --- a/src/main/java/com/chlorocode/tendertracker/service/UserRoleServiceImpl.java +++ b/src/main/java/com/chlorocode/tendertracker/service/UserRoleServiceImpl.java @@ -11,12 +11,10 @@ import org.springframework.stereotype.Service; import javax.transaction.Transactional; -import java.util.Date; -import java.util.LinkedList; -import java.util.List; +import java.util.*; /** - * Created by andy on 27/7/2017. + * Implementation of UserRoleService. */ @Service public class UserRoleServiceImpl implements UserRoleService { @@ -24,6 +22,12 @@ public class UserRoleServiceImpl implements UserRoleService { private UserRoleDAO userRoleDao; private UserDAO userDAO; + /** + * Constructor. + * + * @param userRoleDao UserRoleDAO + * @param userDAO UserDAO + */ @Autowired public UserRoleServiceImpl(UserRoleDAO userRoleDao, UserDAO userDAO){ this.userRoleDao = userRoleDao; @@ -83,4 +87,38 @@ public void removeUserFromCompany(User user, Company company) { List userRoles = userRoleDao.findUserRoleByUserAndCompany(user.getId(), company.getId()); userRoleDao.delete(userRoles); } + + @Override + public Set findCompanyAdminEmails(int companyId) { + List adminUserRoles = userRoleDao.findCompanyAdminUserRole(companyId); + if (adminUserRoles != null) { + Set adminEmails = new HashSet<>(); + for(UserRole admin : adminUserRoles) { + if (admin.getUser() != null && admin.getUser().getEmail() != null) { + adminEmails.add(admin.getUser().getEmail()); + } + } + if (adminEmails.size() > 0) { + return adminEmails; + } + } + return null; + } + + @Override + public Set findCompanyUserEmails(int companyId) { + List userRoles = userRoleDao.findUserRoleByCompany(companyId); + if (userRoles != null) { + Set emails = new HashSet<>(); + for(UserRole admin : userRoles) { + if (admin.getUser() != null && admin.getUser().getEmail() != null) { + emails.add(admin.getUser().getEmail()); + } + } + if (emails.size() > 0) { + return emails; + } + } + return null; + } } diff --git a/src/main/java/com/chlorocode/tendertracker/service/UserService.java b/src/main/java/com/chlorocode/tendertracker/service/UserService.java index b1926a5..1216efa 100644 --- a/src/main/java/com/chlorocode/tendertracker/service/UserService.java +++ b/src/main/java/com/chlorocode/tendertracker/service/UserService.java @@ -4,24 +4,82 @@ import java.util.Optional; +/** + * Service interface of user. + */ public interface UserService { + /** + * This method is used to create a new user. + * + * @param user user object + * @return User + */ User create(User user); + /** + * This method is used to find a user by id. + * + * @param id unique identifier of the user + * @return User + */ User findById(int id); + /** + * This method is used to send password reset pin to user via email. + * + * @param email user email address + * @return String + */ String sendPasswordResetPIN(String email); + /** + * This method is used to find user by email. + * + * @param email user email address + * @return User + */ Optional findByEmail(String email); + /** + * This method is used to validate PIN sent to user. + * + * @param email user email address + * @param pin pin number + * @return boolean + */ boolean isPinValid(String email, String pin); + /** + * This method is used to update user password. + * + * @param email user email address + * @param newPassword new password + * @return User + */ User updatePassword(String email, String newPassword); + /** + * This method is used to update user profile. + * + * @param user user object + * @return User + */ User updateUserProfile(User user); + /** + * This method is used to validate NRIC number. + * + * @param nric NRIC number + * @return boolean + */ boolean isNRICValid(String nric); + /** + * This method is used to validate FIN number. + * @param fin FIN number + * @return boolean + */ boolean isFINValid(String fin); } diff --git a/src/main/java/com/chlorocode/tendertracker/service/UserServiceImpl.java b/src/main/java/com/chlorocode/tendertracker/service/UserServiceImpl.java index 9e31c66..9cb40a4 100644 --- a/src/main/java/com/chlorocode/tendertracker/service/UserServiceImpl.java +++ b/src/main/java/com/chlorocode/tendertracker/service/UserServiceImpl.java @@ -6,10 +6,8 @@ import com.chlorocode.tendertracker.dao.UserRoleDAO; import com.chlorocode.tendertracker.dao.entity.User; import com.chlorocode.tendertracker.exception.ApplicationException; - import com.chlorocode.tendertracker.service.notification.NotificationService; import com.chlorocode.tendertracker.service.notification.NotificationServiceImpl; - import com.chlorocode.tendertracker.utils.DateUtility; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.crypto.password.PasswordEncoder; @@ -17,6 +15,9 @@ import java.util.*; +/** + * Service implementation of UserService. + */ @Service public class UserServiceImpl implements UserService { @@ -27,6 +28,14 @@ public class UserServiceImpl implements UserService { private String className; private NotificationService notificationService; + /** + * Constructor. + * + * @param userDAO UserDAO + * @param passwordEncoder PasswordEncoder + * @param userRoleDAO RoleUserDAO + * @param notificationService NotificationService + */ @Autowired public UserServiceImpl(UserDAO userDAO, PasswordEncoder passwordEncoder,RoleUserDAO userRoleDAO, NotificationService notificationService) { this.userDAO = userDAO; @@ -132,6 +141,12 @@ public String sendPasswordResetPIN(String email) { return "No account found for that email address."; } + /** + * This method is used to generate random PIN number + * + * @param length length of PIN number expected + * @return String + */ private static String generatePIN(int length) { // do not use I, O as looks like 1 and 0 String pin = TTConstants.EMPTY; diff --git a/src/main/java/com/chlorocode/tendertracker/service/notification/MailSenderService.java b/src/main/java/com/chlorocode/tendertracker/service/notification/MailSenderService.java index 5a31c98..101e5de 100644 --- a/src/main/java/com/chlorocode/tendertracker/service/notification/MailSenderService.java +++ b/src/main/java/com/chlorocode/tendertracker/service/notification/MailSenderService.java @@ -1,9 +1,27 @@ package com.chlorocode.tendertracker.service.notification; /** - * Kyaw Min Thu + * Service interface for sending email. */ public interface MailSenderService { - public boolean sendEmail(String subject, String body, String... emails); - public boolean sendEmail(String subject, String templatePath, String[] emails, String... params); + + /** + * This method is used to send email without by direct content without using template. + * @param subject email subject + * @param body email body + * @param emails receiver email address + * @return boolean + */ + boolean sendEmail(String subject, String body, String... emails); + + /** + * This method is used to send email by using email template. + * + * @param subject email subject + * @param templatePath email template path + * @param emails list of receiver email address + * @param params email template parameters + * @return boolean + */ + boolean sendEmail(String subject, String templatePath, String[] emails, String... params); } diff --git a/src/main/java/com/chlorocode/tendertracker/service/notification/MailSenderServiceImpl.java b/src/main/java/com/chlorocode/tendertracker/service/notification/MailSenderServiceImpl.java index 61e4185..fdb7858 100644 --- a/src/main/java/com/chlorocode/tendertracker/service/notification/MailSenderServiceImpl.java +++ b/src/main/java/com/chlorocode/tendertracker/service/notification/MailSenderServiceImpl.java @@ -15,7 +15,7 @@ import java.util.Scanner; /** - * Kyaw Min Thu + * Service implementation of MailSenderService */ @Component public class MailSenderServiceImpl implements MailSenderService { @@ -35,7 +35,7 @@ public boolean sendEmail(String subject, String body, String... emails) { // use the true flag to indicate you need a multipart message MimeMessageHelper helper = new MimeMessageHelper(message, true); - helper.setTo(emails); + helper.setBcc(emails); helper.setSubject(subject); // use the true flag to indicate the text included is HTML @@ -59,7 +59,7 @@ public boolean sendEmail(String subject, String templatePath, String[] emails, S // use the true flag to indicate you need a multipart message MimeMessageHelper helper = new MimeMessageHelper(message, true); helper.setFrom(fromAccount); - helper.setTo(emails); + helper.setBcc(emails); helper.setSubject(subject); // use the true flag to indicate the text included is HTML diff --git a/src/main/java/com/chlorocode/tendertracker/service/notification/NotificationService.java b/src/main/java/com/chlorocode/tendertracker/service/notification/NotificationService.java index d5f7db3..222df67 100644 --- a/src/main/java/com/chlorocode/tendertracker/service/notification/NotificationService.java +++ b/src/main/java/com/chlorocode/tendertracker/service/notification/NotificationService.java @@ -3,8 +3,15 @@ import java.util.Map; /** - * Kyaw Min Thu + * Service interface for notification service. */ public interface NotificationService { + + /** + * This method is used to send notification to user. + * + * @param mode notification mode + * @param params parameters + */ void sendNotification(NotificationServiceImpl.NOTI_MODE mode, Map params); } diff --git a/src/main/java/com/chlorocode/tendertracker/service/notification/NotificationServiceImpl.java b/src/main/java/com/chlorocode/tendertracker/service/notification/NotificationServiceImpl.java index d2a050c..722a160 100644 --- a/src/main/java/com/chlorocode/tendertracker/service/notification/NotificationServiceImpl.java +++ b/src/main/java/com/chlorocode/tendertracker/service/notification/NotificationServiceImpl.java @@ -11,7 +11,7 @@ import java.util.Map; /** - * Kyaw Min Thu + * Service implementation of NotificationService. */ @Component @EnableConfigurationProperties(MailProperties.class) @@ -30,10 +30,25 @@ public enum NOTI_MODE { reset_otp, decision_noti, company_reg_noti, - // TODO add other mode such as tender_noti, etc... + tender_closed_noti, + + company_blacklisted_noti, + + milestone_approach_noti, + appeal_create_noti, + appeal_update_noti, + + tender_award_noti, + other; } + /** + * Constructor. + * + * @param mailSenderManager MailSenderService + * @param mailProperties MailProperties + */ @Autowired public NotificationServiceImpl (MailSenderService mailSenderManager, MailProperties mailProperties) { this.mailSenderManager = mailSenderManager; @@ -54,11 +69,29 @@ public void sendNotification(NOTI_MODE mode, Map params) { sendCompanyReviewedNotiMsg(params); } else if (mode == NOTI_MODE.company_reg_noti) { sendCompanyRegisteredNotiMsg(params); + } else if (mode == NOTI_MODE.tender_closed_noti) { + sendTenderClosedNotiMsg(params); + } else if (mode == NOTI_MODE.company_blacklisted_noti) { + sendCompanyBlackListedNotiMsg(params); + } else if (mode == NOTI_MODE.milestone_approach_noti) { + sendMilestoneApproachNotiMsg(params); + } else if (mode == NOTI_MODE.appeal_create_noti) { + sendAppealCreateNotiMsg(params); + } else if (mode == NOTI_MODE.appeal_update_noti) { + sendAppealUpdateNotiMsg(params); + } else if (mode == NOTI_MODE.tender_award_noti) { + sendTenderAwardNotiMsg(params); } else { //sendEmail("Email Subject","Email body", (String)params.get(TTConstants.PARAM_EMAIL)); } } + /** + * This method is used to send OTP email. + * + * @param params parameters + * @return boolean + */ public boolean sendOTP(Map params) { String name = (String) params.get(TTConstants.PARAM_NAME); String email = (String) params.get(TTConstants.PARAM_EMAIL); @@ -66,13 +99,25 @@ public boolean sendOTP(Map params) { return sendEmail(mailProperties.getSubOTP(), mailProperties.getTemplateOTP(), new String[]{email}, name, email, token, email, token); } + /** + * This method is used to send welcome email. + * + * @param params parameters + * @return boolean + */ public boolean sendWelcomeMsg(Map params) { String name = (String) params.get(TTConstants.PARAM_NAME); String email = (String) params.get(TTConstants.PARAM_EMAIL); return sendEmail(mailProperties.getSubWelcome(), mailProperties.getTemplateWelcome(), new String[]{email}, name); } - public boolean sendBookmarkNotiMsg(Map params) { + /** + * This method is used to send tender update notification email to user who bookmark the tender. + * + * @param params parameters + * @return boolean + */ + public boolean sendBookmarkNotiMsg(Map params) { String id = String.valueOf(params.get(TTConstants.PARAM_TENDER_ID)); String title = (String) params.get(TTConstants.PARAM_TENDER_TITLE); int changeType = (int) params.get(TTConstants.PARAM_CHANGE_TYPE); @@ -84,14 +129,55 @@ public boolean sendBookmarkNotiMsg(Map params) { } } - public boolean sendTenderCreateNotiMsg(Map params) { + /** + * This method is used to send email notification to category subscriber that a new tender has been created. + * + * @param params parameters + * @return boolean + */ + public boolean sendTenderCreateNotiMsg(Map params) { + String id = String.valueOf(params.get(TTConstants.PARAM_TENDER_ID)); + String title = (String) params.get(TTConstants.PARAM_TENDER_TITLE); + String[] emails = (String[]) params.get(TTConstants.PARAM_EMAILS); + return sendEmail(mailProperties.getSubCreateTender(), mailProperties.getTemplateCreateTender(), emails, title, id, id); + } + + /** + * This method is used to send email notification to company administrator that tender has been closed and ready for evaluation. + * + * @param params parameters + * @return boolean + */ + public boolean sendTenderClosedNotiMsg(Map params) { String id = String.valueOf(params.get(TTConstants.PARAM_TENDER_ID)); String title = (String) params.get(TTConstants.PARAM_TENDER_TITLE); String[] emails = (String[]) params.get(TTConstants.PARAM_EMAILS); - return sendEmail(mailProperties.getSubCreateTender(), mailProperties.getTemplateCreateTender(), emails, title, id, (String)id); + return sendEmail(mailProperties.getSubClosedTender(), mailProperties.getTemplateClosedTender() + , emails, title, id, id); } - public boolean sendCompanyReviewedNotiMsg(Map params) { + /** + * This method is used to send email notification to bidder and subscriber that the tender has been awarded. + * + * @param params parameters + * @return boolean + */ + public boolean sendTenderAwardNotiMsg(Map params) { + String id = String.valueOf(params.get(TTConstants.PARAM_TENDER_ID)); + String title = (String) params.get(TTConstants.PARAM_TENDER_TITLE); + String companyName = (String) params.get(TTConstants.PARAM_COMPANY_NAME); + String[] emails = (String[]) params.get(TTConstants.PARAM_EMAILS); + return sendEmail(mailProperties.getSubTenderAwarded(), mailProperties.getTemplateTenderAwarded() + , emails, companyName, title, id, id); + } + + /** + * This method is used to send email notification to company owner that the company registration is accepted / rejected. + * + * @param params parameters + * @return boolean + */ + public boolean sendCompanyReviewedNotiMsg(Map params) { String id = String.valueOf(params.get(TTConstants.PARAM_COMPANY_ID)); String name = (String) params.get(TTConstants.PARAM_COMPANY_NAME); String action = (String) params.get(TTConstants.PARAM_APPROVAL_ACTION); @@ -102,6 +188,12 @@ public boolean sendCompanyReviewedNotiMsg(Map params) { , new String[]{email}, name, action, id, id); } + /** + * This method is used to send email notification that company registration has been created and pending approval. + * + * @param params parameters + * @return boolean + */ public boolean sendCompanyRegisteredNotiMsg(Map params) { Company company = (Company) params.get(TTConstants.PARAM_COMPANY); String email = (String) params.get(TTConstants.PARAM_EMAIL); @@ -109,6 +201,70 @@ public boolean sendCompanyRegisteredNotiMsg(Map params) { new String[]{email}, company.getName()); } + /** + * This method is used to notify company owner that the company has been blacklisted. + * + * @param params parameters + * @return boolean + */ + public boolean sendCompanyBlackListedNotiMsg(Map params) { + Company company = (Company) params.get(TTConstants.PARAM_COMPANY); + String[] emails = (String[]) params.get(TTConstants.PARAM_EMAILS); + return sendEmail(mailProperties.getSubCompanyBlacklisted(), mailProperties.getTemplateCompanyBlacklisted(), + emails, company.getName()); + } + + /** + * This method is used to send email notification to company admin that tender milestone is approaching. + * + * @param params parameters + * @return boolean + */ + public boolean sendMilestoneApproachNotiMsg(Map params) { + String id = String.valueOf(params.get(TTConstants.PARAM_TENDER_ID)); + String title = (String) params.get(TTConstants.PARAM_TENDER_TITLE); + String description = (String) params.get(TTConstants.PARAM_MILESTONE_DESCRIPTION); + String dueDate = (String) params.get(TTConstants.PARAM_MILESTONE_DUE_DATE); + String status = (String) params.get(TTConstants.PARAM_MILESTONE_STATUS); + String[] emails = (String[]) params.get(TTConstants.PARAM_EMAILS); + return sendEmail(mailProperties.getSubMilestoneApproach() + , mailProperties.getTemplateMilestoneApproach() + , emails, description, title, dueDate, status, id, id); + } + + /** + * This method is used to send email notification to company admin that a new tender appeal has been created. + * + * @param params parameters + * @return boolean + */ + public boolean sendAppealCreateNotiMsg(Map params) { + String id = String.valueOf(params.get(TTConstants.PARAM_TENDER_ID)); + String title = (String) params.get(TTConstants.PARAM_TENDER_TITLE); + String appealCompany = (String) params.get(TTConstants.PARAM_APPEAL_COMPANY); + String[] emails = (String[]) params.get(TTConstants.PARAM_EMAILS); + return sendEmail(mailProperties.getSubAppealCreate(), mailProperties.getTemplateAppealCreate(), emails, appealCompany, title, id, id); + } + + /** + * This method is used to send email notification to tender appeal submitter about the updated appeal status. + * + * @param params parameters + * @return boolean + */ + public boolean sendAppealUpdateNotiMsg(Map params) { + String id = String.valueOf(params.get(TTConstants.PARAM_TENDER_ID)); + String title = (String) params.get(TTConstants.PARAM_TENDER_TITLE); + String appealCompany = (String) params.get(TTConstants.PARAM_APPEAL_COMPANY); + int action = (int) params.get(TTConstants.PARAM_APPEAL_ACTION); + String[] emails = (String[]) params.get(TTConstants.PARAM_EMAILS); + if (action == TTConstants.APPEAL_ACCEPT) { + return sendEmail(mailProperties.getSubAppealAccepted(), mailProperties.getTemplateAppealAccepted(), emails, appealCompany, title, id, id); + } else { + return sendEmail(mailProperties.getSubAppealRejected(), mailProperties.getTemplateAppealRejected(), emails, appealCompany, title, id, id); + } + } + private boolean sendEmail(String emailSubject, String path, String[] to, String... params) { return mailSenderManager.sendEmail(emailSubject, path, to, params); } diff --git a/src/main/java/com/chlorocode/tendertracker/utils/DateUtility.java b/src/main/java/com/chlorocode/tendertracker/utils/DateUtility.java index 68f645f..105d184 100644 --- a/src/main/java/com/chlorocode/tendertracker/utils/DateUtility.java +++ b/src/main/java/com/chlorocode/tendertracker/utils/DateUtility.java @@ -5,15 +5,36 @@ import java.time.ZoneId; import java.util.Date; +/** + * Utility class for Date. + */ public class DateUtility { + /** + * This method is used to get current date with 00 hour 00 minute 00 second. + * @return Date + */ public static final Date getCurrentDate() { - return Date.from(LocalDate.now().atStartOfDay(ZoneId.systemDefault()).toInstant()); + Date date = Date.from(LocalDate.now().atStartOfDay(ZoneId.systemDefault()).toInstant()); + return date; } + /** + * This method is used to get current date. + * @return Date + */ public static final Date getCurrentDateTime() { return Date.from(LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant()); } + /** + * This method used to get result date after add or subtract the params(years or days or hour or minutes) + * + * @param years desired +/-years + * @param days desired +/-days + * @param hours desired +/-hours + * @param minutes desired +/-minutes + * @return Date + */ public static final Date getFutureDateTime(int years, int days, int hours, int minutes) { LocalDateTime tokenExpirationDate = LocalDateTime.now(); if (years > 0) { diff --git a/src/main/java/com/chlorocode/tendertracker/utils/TTCommonUtil.java b/src/main/java/com/chlorocode/tendertracker/utils/TTCommonUtil.java new file mode 100644 index 0000000..3a62f27 --- /dev/null +++ b/src/main/java/com/chlorocode/tendertracker/utils/TTCommonUtil.java @@ -0,0 +1,40 @@ +package com.chlorocode.tendertracker.utils; + +import com.chlorocode.tendertracker.constants.TTConstants; + +/** + * Utility for common usage. + */ +public class TTCommonUtil { + /** + * This method is use to get convert the String of the status from status code. + * + * @param statusCode status code of external tender + * @return String + */ + public static String getExternalTenderStatus(int statusCode) { + switch (statusCode) { + case 1 : return TTConstants.ET_STATUS_OPEN; + case 2 : return TTConstants.ET_STATUS_CLOSED; + case 3 : return TTConstants.ET_STATUS_AWARDED; + case 4 : return TTConstants.ET_STATUS_NO_AWARD; + case 5 : + default: return TTConstants.ET_STATUS_OTHERS; + } + } + + /** + * This method is used to create the like query pattern.(for eg- '%searchTerm%' + * + * @param searchTerm search free text + * @return String + */ + public static String getContainsLikePattern(String searchTerm) { + if (searchTerm == null || searchTerm.isEmpty()) { + return "%"; + } + else { + return "%" + searchTerm.toLowerCase() + "%"; + } + } +} diff --git a/src/main/java/com/chlorocode/tendertracker/web/AuthController.java b/src/main/java/com/chlorocode/tendertracker/web/AuthController.java index f55b72c..ddb98ba 100644 --- a/src/main/java/com/chlorocode/tendertracker/web/AuthController.java +++ b/src/main/java/com/chlorocode/tendertracker/web/AuthController.java @@ -10,7 +10,6 @@ import com.chlorocode.tendertracker.service.CompanyService; import com.chlorocode.tendertracker.service.UserRoleService; import com.chlorocode.tendertracker.service.UserService; -import com.chlorocode.tendertracker.service.notification.NotificationService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; @@ -29,40 +28,54 @@ import java.util.List; import java.util.Map; +/** + * Controller for authentication and administration. + */ @Controller public class AuthController { private UserService userService; private UserRoleService userRoleService; private CompanyService companyService; - private NotificationService notificationService; private CodeValueService codeValueService; + /** + * Constructor + * + * @param userService UserService + * @param companyService CompanyService + * @param codeValueService CodeValueService + * @param userRoleService UserRoleService + */ @Autowired - public AuthController(UserService userService, CompanyService companyService, NotificationService notificationService, + public AuthController(UserService userService, CompanyService companyService, CodeValueService codeValueService, UserRoleService userRoleService) { this.userService = userService; this.companyService = companyService; - this.notificationService = notificationService; this.codeValueService = codeValueService; this.userRoleService = userRoleService; } + /** + * This method is used to show login screen. + * + * @param request ServletRequest + * @param model Model + * @return String + */ @RequestMapping("/login") public String showLogin(ServletRequest request, Model model) { - Map paramMap = request.getParameterMap(); - -// if (paramMap.containsKey("error")) -// { -// AlertDTO alert = new AlertDTO(AlertDTO.AlertType.DANGER, -// "Invalid username or password"); -// model.addAttribute("alert", alert); -// } model.addAttribute("login", new LoginDTO()); return "login"; } + /** + * This method is used to show user registration screen. + * + * @param model ModelMap + * @return ModelAndView + */ @GetMapping("/register") public ModelAndView showUserRegistration(ModelMap model) { model.addAttribute("IdType",codeValueService.getByType("id_type")); @@ -70,6 +83,16 @@ public ModelAndView showUserRegistration(ModelMap model) { } + /** + * This method is used to register user. + * + * @param form UserRegistrationDTO + * @param result BindingResult + * @param redirectAttrs RedirectAttributes + * @param model ModelMap + * @return String + * @see UserRegistrationDTO + */ @PostMapping("/register") public String saveUserRegistration(@Valid @ModelAttribute("registration") UserRegistrationDTO form, BindingResult result, RedirectAttributes redirectAttrs, ModelMap model) { @@ -128,6 +151,11 @@ public String saveUserRegistration(@Valid @ModelAttribute("registration") UserRe return "redirect:/login"; } + /** + * This method is used to show select company screen. + * + * @return ModelAndView + */ @GetMapping("/selectCompany") public ModelAndView showSelectCompany() { Authentication auth = SecurityContextHolder.getContext().getAuthentication(); @@ -137,6 +165,12 @@ public ModelAndView showSelectCompany() { return new ModelAndView("selectCompany", "company", administeredCompanies); } + /** + * This method is used to select company for managing. + * + * @param companyId unique identifier of the company + * @return String + */ @PostMapping("/selectCompany") public String selectCompanyToManage(@RequestParam("companyId") String companyId) { Authentication auth = SecurityContextHolder.getContext().getAuthentication(); @@ -157,6 +191,13 @@ public String selectCompanyToManage(@RequestParam("companyId") String companyId) return "redirect:/"; } + /** + * This method used to show forgot password screen. + * + * @param request ServletRequest + * @param model Model + * @return String + */ @RequestMapping("/forgotPassword") public String forgotPassword(ServletRequest request, Model model) { Map paramMap = request.getParameterMap(); @@ -165,6 +206,16 @@ public String forgotPassword(ServletRequest request, Model model) { return "forgotPassword"; } + /** + * This method used to send PIN for identifying user email. + * + * @param form ForgotPasswordDTO + * @param result BindingResult + * @param redirectAttrs RedirectAttributes + * @param model ModelMap + * @return String + * @see ForgotPasswordDTO + */ @RequestMapping("/sendPIN") public String sendPIN(@Valid @ModelAttribute("forgotPassword") ForgotPasswordDTO form, BindingResult result, RedirectAttributes redirectAttrs, ModelMap model) { @@ -189,6 +240,15 @@ public String sendPIN(@Valid @ModelAttribute("forgotPassword") ForgotPasswordDTO return "forgotPassword"; } + /** + * This method is used to reset the user password. + * + * @param email email address of the user + * @param pin pin number of the user for identifying user + * @param request ServletRequest + * @param model Model + * @return String + */ @GetMapping("/resetPassword/{email}/{pin}") public String resetPassword(@PathVariable(value="email") String email, @PathVariable(value="pin") String pin, ServletRequest request, Model model) { ChangePasswordDTO dto = new ChangePasswordDTO(); @@ -206,6 +266,16 @@ public String resetPassword(@PathVariable(value="email") String email, @PathVari return "changePassword"; } + /** + * This method is used to change the user password. + * + * @param form ChangePasswordDTO + * @param result BindingResult + * @param redirectAttrs RedirectAttributes + * @param model ModelMap + * @return String + * @see ChangePasswordDTO + */ @RequestMapping("/changePassword") public String changePassword(@Valid @ModelAttribute("changePassword") ChangePasswordDTO form , BindingResult result, RedirectAttributes redirectAttrs, ModelMap model) { diff --git a/src/main/java/com/chlorocode/tendertracker/web/CompanyController.java b/src/main/java/com/chlorocode/tendertracker/web/CompanyController.java index dd6f7a3..14a1178 100644 --- a/src/main/java/com/chlorocode/tendertracker/web/CompanyController.java +++ b/src/main/java/com/chlorocode/tendertracker/web/CompanyController.java @@ -8,6 +8,7 @@ import com.chlorocode.tendertracker.exception.ApplicationException; import com.chlorocode.tendertracker.service.CodeValueService; import com.chlorocode.tendertracker.service.CompanyService; +import com.chlorocode.tendertracker.service.UenEntityService; import com.chlorocode.tendertracker.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.Authentication; @@ -22,22 +23,40 @@ import org.springframework.web.servlet.mvc.support.RedirectAttributes; import javax.validation.Valid; -import java.util.List; +/** + * Controller for the company management. + */ @Controller public class CompanyController { private CodeValueService codeValueService; private CompanyService companyService; private UserService userService; - + private UenEntityService uenEntService; + + /** + * Constructor. + * + * @param codeValueService CodeValueService + * @param companyService CompanyService + * @param userService UserService + * @param uenEntService UenEntityService + */ @Autowired - public CompanyController(CodeValueService codeValueService, CompanyService companyService, UserService userService) { + public CompanyController(CodeValueService codeValueService, CompanyService companyService, UserService userService, UenEntityService uenEntService) { this.codeValueService = codeValueService; this.companyService = companyService; this.userService = userService; + this.uenEntService = uenEntService; } + /** + * This method is used to show company registration screen. + * + * @param model ModelMap + * @return String + */ @GetMapping("registerCompany") public String showRegisterCompany(ModelMap model) { CompanyRegistrationDTO dto = new CompanyRegistrationDTO(); @@ -50,6 +69,16 @@ public String showRegisterCompany(ModelMap model) { return "registerCompany"; } + /** + * This method is used to register the company. + * + * @param form CompanyRegistrationDTO + * @param result BindingResult + * @param redirectAttrs RedirectAttributes + * @param model ModelMap + * @return String + * @see CompanyRegistrationDTO + */ @PostMapping("registerCompany") public String saveCompanyRegistration(@Valid @ModelAttribute("registration") CompanyRegistrationDTO form, BindingResult result, RedirectAttributes redirectAttrs, ModelMap model) { @@ -63,19 +92,6 @@ public String saveCompanyRegistration(@Valid @ModelAttribute("registration") Com return "registerCompany"; } - List compList = companyService.findCompanyByUen(form.getUen()); - - if(compList != null && compList.size() > 0){ - AlertDTO alert = new AlertDTO(AlertDTO.AlertType.DANGER, - "This company UEN already exist"); - model.addAttribute("alert", alert); - model.addAttribute("registration", form); - model.addAttribute("areaOfBusiness", codeValueService.getByType("area_of_business")); - model.addAttribute("companyType", codeValueService.getByType("company_type")); - model.addAttribute("countries", codeValueService.getAllCountries()); - return "registerCompany"; - } - Company reg = new Company(); reg.setName(form.getName()); reg.setUen(form.getUen()); @@ -102,7 +118,17 @@ public String saveCompanyRegistration(@Valid @ModelAttribute("registration") Com reg.setLastUpdatedBy(usr.getUser().getId()); try { - companyService.registerCompany(reg); + String errMsg = companyService.registerCompany(reg); + if(errMsg != null){ + AlertDTO alert = new AlertDTO(AlertDTO.AlertType.DANGER, + errMsg); + model.addAttribute("alert", alert); + model.addAttribute("registration", form); + model.addAttribute("areaOfBusiness", codeValueService.getByType("area_of_business")); + model.addAttribute("companyType", codeValueService.getByType("company_type")); + model.addAttribute("countries", codeValueService.getAllCountries()); + return "registerCompany"; + } } catch (ApplicationException ex) { AlertDTO alert = new AlertDTO(AlertDTO.AlertType.DANGER, ex.getMessage()); model.addAttribute("alert", alert); @@ -119,6 +145,13 @@ public String saveCompanyRegistration(@Valid @ModelAttribute("registration") Com return "redirect:/"; } + /** + * This method is used to show the company detail screen. + * + * @param id unique identifier of the company. + * @param model ModelMap + * @return String + */ @GetMapping("/company/{id}") public String showCompanyDetail(@PathVariable(value = "id") Integer id, ModelMap model) { Company company = companyService.findById(id); diff --git a/src/main/java/com/chlorocode/tendertracker/web/GlobalControllerExceptionHandler.java b/src/main/java/com/chlorocode/tendertracker/web/GlobalControllerExceptionHandler.java new file mode 100644 index 0000000..301c10b --- /dev/null +++ b/src/main/java/com/chlorocode/tendertracker/web/GlobalControllerExceptionHandler.java @@ -0,0 +1,28 @@ +package com.chlorocode.tendertracker.web; + +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; + +import javax.servlet.http.HttpServletRequest; + +/** + * This class is used to handle the exception of whole application. + */ +@ControllerAdvice +class GlobalControllerExceptionHandler { + /** + * This method is used to control the exception as default. + * @param req HttpServletRequest + * @param e Exception + * @return String + * @throws Exception Exception + */ + @ExceptionHandler(value = Exception.class) + public String defaultErrorHandler(HttpServletRequest req, Exception e) throws Exception { + // If the exception is annotated with @ResponseStatus rethrow it and let + // the framework handle it - like the OrderNotFoundException example + // at the start of this post. + // AnnotationUtils is a Spring Framework utility class. + return "error/error"; + } +} diff --git a/src/main/java/com/chlorocode/tendertracker/web/HomeController.java b/src/main/java/com/chlorocode/tendertracker/web/HomeController.java index 6d6de32..1119297 100644 --- a/src/main/java/com/chlorocode/tendertracker/web/HomeController.java +++ b/src/main/java/com/chlorocode/tendertracker/web/HomeController.java @@ -4,8 +4,11 @@ import com.chlorocode.tendertracker.dao.dto.AlertDTO; import com.chlorocode.tendertracker.dao.dto.Pager; import com.chlorocode.tendertracker.dao.dto.TenderSearchDTO; +import com.chlorocode.tendertracker.dao.entity.ExternalTender; import com.chlorocode.tendertracker.dao.entity.Tender; +import com.chlorocode.tendertracker.logging.TTLogger; import com.chlorocode.tendertracker.service.CodeValueService; +import com.chlorocode.tendertracker.service.ExternalTenderService; import com.chlorocode.tendertracker.service.TenderService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; @@ -18,43 +21,58 @@ import java.util.Optional; +/** + * Controller class for user home screen. + */ @Controller public class HomeController { private TenderService tenderService; + private ExternalTenderService externalTenderService; private CodeValueService codeValueService; + /** + * Constructor. + * + * @param tenderService TenderService + * @param codeValueService CodeValueService + * @param externalTenderService ExternalTenderService + */ @Autowired - public HomeController(TenderService tenderService, CodeValueService codeValueService) { + public HomeController(TenderService tenderService, CodeValueService codeValueService, ExternalTenderService externalTenderService) { this.tenderService = tenderService; this.codeValueService = codeValueService; + this.externalTenderService = externalTenderService; } /** - * Handles all requests + * This method is used to show home page. * - * @param pageSize - * @param page - * @return model and view + * @param pageSize size of the page + * @param page current page + * @param model modelMap + * @return String */ @GetMapping("/") - public String showPersonsPage(@RequestParam("pageSize") Optional pageSize, + public String showHomePage(@RequestParam("pageSize") Optional pageSize, @RequestParam("page") Optional page, ModelMap model) { - // Evaluate page size. If requested parameter is null, return initial - // page size + // Evaluate page size. If requested parameter is null, return initial page size int evalPageSize = pageSize.orElse(TTConstants.INITIAL_PAGE_SIZE); - // Evaluate page. If requested parameter is null or less than 0 (to - // prevent exception), return initial size. Otherwise, return value of - // param. decreased by 1. + /* + Evaluate page. If requested parameter is null or less than 0 (to + prevent exception), return initial size. Otherwise, return value of + param. decreased by 1. + */ int evalPage = (page.orElse(0) < 1) ? TTConstants.INITIAL_PAGE : page.get() - 1; Page tenders = tenderService.listAllByPage( new PageRequest( - evalPage, evalPageSize, new Sort(new Sort.Order(Sort.Direction.ASC, TTConstants.OPEN_DATE)) + evalPage, evalPageSize, new Sort(new Sort.Order(Sort.Direction.DESC, TTConstants.OPEN_DATE)) )); Pager pager = new Pager(tenders.getTotalPages(), tenders.getNumber(), TTConstants.BUTTONS_TO_SHOW); TenderSearchDTO tenderSearchDTO = new TenderSearchDTO(); tenderSearchDTO.setOrderBy(TTConstants.OPEN_DATE); + tenderSearchDTO.setOrderMode(TTConstants.DESC); model.addAttribute("tenders", tenders); model.addAttribute("searchCriteria", tenderSearchDTO); model.addAttribute("codeValueSvc", codeValueService); @@ -68,6 +86,58 @@ evalPage, evalPageSize, new Sort(new Sort.Order(Sort.Direction.ASC, TTConstants. return "home"; } + /** + * This method is used to show eligible external tender. + * + * @param pageSize size of the page + * @param page current page + * @param model ModelMap + * @return String + */ + @GetMapping("/external_tender") + public String showExternalTender(@RequestParam("pageSize") Optional pageSize, + @RequestParam("page") Optional page, ModelMap model) { + // Evaluate page size. If requested parameter is null, return initial page size + int evalPageSize = pageSize.orElse(TTConstants.INITIAL_PAGE_SIZE); + + /* + Evaluate page. If requested parameter is null or less than 0 (to + prevent exception), return initial size. Otherwise, return value of + param. decreased by 1. + */ + int evalPage = (page.orElse(0) < 1) ? TTConstants.INITIAL_PAGE : page.get() - 1; + + Page externalTenders = externalTenderService.listAllByPage( + new PageRequest( + evalPage, evalPageSize, new Sort(new Sort.Order(Sort.Direction.DESC, TTConstants.PUBLISHED_DATE)) + )); + Pager pager = new Pager(externalTenders.getTotalPages(), externalTenders.getNumber(), TTConstants.BUTTONS_TO_SHOW); + + for (ExternalTender exTender : externalTenders.getContent()) { + TTLogger.debug(HomeController.class.getName(), "****ExternalTender="+exTender.toString()); + } + + TenderSearchDTO tenderSearchDTO = new TenderSearchDTO(); + tenderSearchDTO.setOrderBy(TTConstants.OPEN_DATE); + tenderSearchDTO.setOrderMode(TTConstants.DESC); + model.addAttribute("external_tenders", externalTenders); + model.addAttribute("searchCriteria", tenderSearchDTO); + model.addAttribute("codeValueSvc", codeValueService); + model.addAttribute("selectedPageSize", evalPageSize); + model.addAttribute("pager", pager); + if (externalTenders == null || externalTenders.getTotalPages() == 0) { + AlertDTO alert = new AlertDTO(AlertDTO.AlertType.WARNING, + "No tenders found."); + model.addAttribute("alert", alert); + } + return "external_tenders"; + } + + /** + * This method is used to show about page of the website. + * + * @return String + */ @GetMapping("/about") public String showAboutPage() { return "about"; diff --git a/src/main/java/com/chlorocode/tendertracker/web/MarketplaceController.java b/src/main/java/com/chlorocode/tendertracker/web/MarketplaceController.java new file mode 100644 index 0000000..6286300 --- /dev/null +++ b/src/main/java/com/chlorocode/tendertracker/web/MarketplaceController.java @@ -0,0 +1,332 @@ +package com.chlorocode.tendertracker.web; + +import com.chlorocode.tendertracker.constants.TTConstants; +import com.chlorocode.tendertracker.dao.dto.*; +import com.chlorocode.tendertracker.dao.entity.*; +import com.chlorocode.tendertracker.exception.ApplicationException; +import com.chlorocode.tendertracker.logging.TTLogger; +import com.chlorocode.tendertracker.service.CodeValueService; +import com.chlorocode.tendertracker.service.ProductClarificationService; +import com.chlorocode.tendertracker.service.ProductService; +import com.chlorocode.tendertracker.service.UserService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Sort; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.servlet.mvc.support.RedirectAttributes; + +import javax.validation.Valid; +import java.util.Date; +import java.util.List; +import java.util.Optional; + +/** + * Controller for marketplace. + */ +@Controller +public class MarketplaceController { + + private ProductService productService; + private ProductClarificationService prdSvc; + private CodeValueService codeValueService; + private UserService userSvc; + private String className; + + /** + * Constructor. + * + * @param productService ProductService + * @param codeValueService CodeValueService + * @param prdSvc ProductClarificationService + * @param userSvc UserService + */ + @Autowired + public MarketplaceController(ProductService productService, CodeValueService codeValueService,ProductClarificationService prdSvc,UserService userSvc) { + this.productService = productService; + this.codeValueService = codeValueService; + this.prdSvc = prdSvc; + this.userSvc = userSvc; + className = this.getClass().getName(); + } + + /** + * This method is used to show product list screen of marketplace. + * + * @param pageSize size of the page + * @param page current page number + * @param modelMap ModelMap + * @return String + */ + @GetMapping("/marketplace") + public String marketplace(@RequestParam("pageSize") Optional pageSize, + @RequestParam("page") Optional page, + ModelMap modelMap) { + + int evalPageSize = pageSize.orElse(TTConstants.INITIAL_PAGE_SIZE); + int evalPage = (page.orElse(0) < 1) ? TTConstants.INITIAL_PAGE : page.get() - 1; + + Page products = productService.listAllByPage( + new PageRequest( + evalPage, evalPageSize, new Sort(new Sort.Order(Sort.Direction.ASC, TTConstants.TITLE)) + )); + + Pager pager = new Pager(products.getTotalPages(), products.getNumber(), TTConstants.BUTTONS_TO_SHOW); + + ProductSearchDTO productSearchDTO = new ProductSearchDTO(); + productSearchDTO.setOrderBy(TTConstants.TITLE); + productSearchDTO.setOrderMode(TTConstants.ASC); + modelMap.addAttribute("searchCriteria", productSearchDTO); + modelMap.addAttribute("products", products); + modelMap.addAttribute("codeValueSvc", codeValueService); + modelMap.addAttribute("selectedPageSizse", evalPageSize); + modelMap.addAttribute("pager", pager); + + if (products == null || products.getTotalPages() == 0) { + AlertDTO alertDTO = new AlertDTO(AlertDTO.AlertType.WARNING, "No Products found."); + modelMap.addAttribute("alert", alertDTO); + } + + return "marketplace"; + } + + /** + * This method is used to show products list of marketplace by advanced search or searchText. + * + * @param pageSize size of the page + * @param page current page number + * @param searchText free search text + * @param title title of company + * @param companyName company name + * @param orderBy order by + * @param orderMode order mode + * @param modelMap ModelMap + * @return String + */ + @GetMapping("/marketplace/products") + public String showProducts(@RequestParam("pageSize") Optional pageSize, + @RequestParam("page") Optional page, + @RequestParam("searchText") Optional searchText, + @RequestParam("title") Optional title, + @RequestParam("companyName") Optional companyName, + @RequestParam("orderBy") Optional orderBy, + @RequestParam("orderMode") Optional orderMode, + ModelMap modelMap) { + ProductSearchDTO productSearchDTO = new ProductSearchDTO(); + productSearchDTO.setSearchText(searchText.orElse(null)); + productSearchDTO.setTitle(title.orElse(null)); + productSearchDTO.setCompanyName(companyName.orElse(null)); + productSearchDTO.setOrderBy(orderBy.orElse(null) == null ? TTConstants.TITLE : orderBy.get()); + productSearchDTO.setOrderMode(orderMode.orElse(null) == null ? TTConstants.ASC : orderMode.get()); + productSearchDTO.setAdvance(productSearchDTO.getSearchText() != null + || productSearchDTO.getTitle() != null + || productSearchDTO.getCompanyName() != null); + + int evalPageSize = pageSize.orElse(TTConstants.INITIAL_PAGE_SIZE); + int evalPage = (page.orElse(0) < 1) ? TTConstants.INITIAL_PAGE : page.get() - 1; + + Page products = productService.searchProduct(productSearchDTO, +// new PageRequest(evalPage, evalPageSize) + new PageRequest( + evalPage, evalPageSize, getSortPattern(productSearchDTO) + ) + ); + + Pager pager = new Pager(products.getTotalPages(), products.getNumber(), TTConstants.BUTTONS_TO_SHOW); + + modelMap.addAttribute("searchCriteria", productSearchDTO); + modelMap.addAttribute("products", products); + modelMap.addAttribute("codeValueSvc", codeValueService); + modelMap.addAttribute("selectedPageSizse", evalPageSize); + modelMap.addAttribute("pager", pager); + if (products == null || products.getTotalPages() == 0) { + modelMap.addAttribute("noProductFound", true); + } else { + modelMap.addAttribute("noProductFound", false); + } + + return "marketplace"; + } + + /** + * This method is used the get the sort pattern of the product list screen. + * + * @param searchDTO ProductSearchDTO + * @return Sort + * @see ProductSearchDTO + */ + private Sort getSortPattern(ProductSearchDTO searchDTO) { + Sort.Direction direction = Sort.Direction.ASC; + // Set order direction. + if (searchDTO.getOrderMode().equals(TTConstants.DESC)) { + direction = Sort.Direction.DESC; + } + + // Set order by attribute. + return new Sort(new Sort.Order(direction, searchDTO.getOrderBy())); + } + + /** + * This method is used to show the detail screen of selected product. + * + * @param id unique identifier of the product + * @param model ModelMap + * @return String + */ + @GetMapping("/product/clarification/{id}") + public String showProductDetailsPage(@PathVariable(value = "id") Integer id, ModelMap model){ + + Product prod = productService.findById(id); + List prodClar = prdSvc.findClarificationByProdId(id); + ProductUpdateDTO prodDto = new ProductUpdateDTO(); + model.addAttribute("product", prod); + model.addAttribute("productclarification", prod.getClarifications()); + + model.addAttribute("prodDto",prodDto); + model.addAttribute("clarification",prodClar); + return "marketplaceClarification"; + } + + /** + * This method is used to update the product clarification. + * + * @param response description of product clarification + * @param productId unique identifier of the product + * @param redirectAttrs RedirectAttributes + * @return String + */ + @PostMapping("/product/clarification/save") + public String updateProduct (@RequestParam("response") String response, @RequestParam("productId") int productId, RedirectAttributes redirectAttrs) { + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + CurrentUser currentUser = (CurrentUser) authentication.getPrincipal(); + ProductClarification clar = new ProductClarification(); + Company comp = new Company(); + comp.setId(currentUser.getSelectedCompany().getId()); + Product p = new Product(); + p.setProductCode(productId); + clar.setCompany(comp); + clar.setProduct(p); + clar.setCreatedBy(currentUser.getId()); + clar.setCreatedDate(new Date()); + clar.setLastUpdatedBy(currentUser.getId()); + clar.setLastUpdatedDate(new Date()); + clar.setDescription(response); + + try { + prdSvc.create(clar); + } catch (ApplicationException ex) { + AlertDTO alert = new AlertDTO(AlertDTO.AlertType.DANGER, + ex.getMessage()); + redirectAttrs.addFlashAttribute("alert", alert); + return "redirect:/product/clarification/" + productId; + } + + AlertDTO alert = new AlertDTO(AlertDTO.AlertType.SUCCESS, "Product Updated"); + redirectAttrs.addFlashAttribute("alert", alert); + return "redirect:/product/clarification/" + productId; + } + + /** + * This method is used to show the product clarification page. + * + * @return String + */ + @GetMapping("/admin/product/clarification") + public String showProductClarificationPage() { + return "admin/product/productClarificationView"; + } + + /** + * This method is used to show the tender clarification update page. + * + * @param id unique identifier of the product clarification. + * @param model ModelMap + * @return String + */ + @GetMapping("/admin/product/clarification/view/{id}") + public String showTenderClarificationUpdatePage(@PathVariable(value = "id") Integer id,ModelMap model) { + ProductClarification clarfi = prdSvc.findById(id); + if(clarfi == null){ + AlertDTO alert = new AlertDTO(AlertDTO.AlertType.DANGER, + "unable to find the clarification based on this id " + id); + model.addAttribute("alert", alert); + return "admin/clarification/tenderClarificationList"; + } + + //perform validation check, if the tender is not created by this company, stop to view it + CurrentUser usr1 = (CurrentUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); + if(clarfi.getProduct().getCompany().getId() != usr1.getSelectedCompany().getId()) + { + AlertDTO alert = new AlertDTO(AlertDTO.AlertType.DANGER, + "You are not authorized to view the tender clarification details"); + model.addAttribute("alert", alert); + return "admin/clarification/tenderClarificationList"; + } + try{ + User usr = userSvc.findById(clarfi.getCreatedBy()); + TenderClarificationDTO dto = new TenderClarificationDTO(); + dto.setId(clarfi.getId()); + dto.setClarification(clarfi.getDescription()); + dto.setTitle(clarfi.getProduct().getTitle()); + dto.setDescription(clarfi.getProduct().getDescription()); + dto.setSubmittedByCompany(clarfi.getCompany().getName()); + dto.setSubmittedByName(usr.getName()); + dto.setSubmittedByContactNo(usr.getContactNo()); + dto.setSubmittedByEmail(usr.getEmail()); + dto.setSubmittedDate(clarfi.getCreatedDate()); + dto.setResponse(clarfi.getResponse()); + dto.setPrice(clarfi.getProduct().getPrice()); + List lstCode = codeValueService.getByType("product_category"); + for(int i = 0; i < lstCode.size(); i++){ + CodeValue code = lstCode.get(i); + if(code.getCode() == clarfi.getProduct().getCategory()){ + dto.setCategory(code.getDescription()); + break; + } + } + + //dto.setTenderType(clarfi.getTender().getTenderType()); + model.addAttribute("clarificationDto",dto); + }catch(Exception ex){ + TTLogger.error(className,"error: ", ex ); + AlertDTO alert = new AlertDTO(AlertDTO.AlertType.DANGER, + "Failed to retrieve tender clarification.Please contact administrator"); + model.addAttribute("alert", alert); + return "admin/clarification/tenderClarificationList"; + } + + + return "admin/product/productClarificationFormView"; + } + + /** + * This method is used to update the tender clarification response. + * + * @param form TenderClarificationDTO + * @param model ModelMap + * @return String + */ + @PostMapping("/admin/product/clarification/update") + public String updateTenderClarificationResponse(@Valid TenderClarificationDTO form, ModelMap model){ + + ProductClarification clari = prdSvc.updateResponse(form.getId(),form.getResponse()); + if(clari == null){ + AlertDTO alert = new AlertDTO(AlertDTO.AlertType.DANGER, + "Failed to update tender clarification response.Please contact administrator"); + model.addAttribute("alert", alert); + }else{ + AlertDTO alert = new AlertDTO(AlertDTO.AlertType.SUCCESS, + "Update tender clarification response successfully"); + model.addAttribute("alert", alert); + } + + return "admin/product/productClarificationView"; + } +} diff --git a/src/main/java/com/chlorocode/tendertracker/web/TenderPublicController.java b/src/main/java/com/chlorocode/tendertracker/web/TenderPublicController.java index 86a6a07..e7c4a42 100644 --- a/src/main/java/com/chlorocode/tendertracker/web/TenderPublicController.java +++ b/src/main/java/com/chlorocode/tendertracker/web/TenderPublicController.java @@ -4,7 +4,9 @@ import com.chlorocode.tendertracker.dao.dto.*; import com.chlorocode.tendertracker.dao.entity.*; import com.chlorocode.tendertracker.exception.ApplicationException; +import com.chlorocode.tendertracker.logging.TTLogger; import com.chlorocode.tendertracker.service.*; +import com.chlorocode.tendertracker.utils.TTCommonUtil; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; @@ -20,45 +22,91 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; -import java.util.Date; -import java.util.LinkedList; -import java.util.List; -import java.util.Optional; +import java.net.URL; +import java.net.URLConnection; +import java.util.*; +/** + * Controller for tender page in public portal. + */ @Controller public class TenderPublicController { private TenderService tenderService; + private ExternalTenderService externalTenderService; private BidService bidService; private CodeValueService codeValueService; private S3Wrapper s3Wrapper; private ClarificationService clariSvc; private CorrigendumService corrigendumService; + private TenderSubscriptionService tenderSubscriptionService; + private TenderItemService tenderItemService; + /** + * Constructor. + * + * @param tenderService TenderService + * @param externalTenderService ExternalTenderService + * @param bidService BidService + * @param codeValueService CodeValueService + * @param s3Wrapper s3Wrapper + * @param clariSvc ClarificationService + * @param corrigendumService CorrigendumService + * @param tenderSubscriptionService TenderSubscriptionService + * @param tenderItemService TenderItemService + */ @Autowired - public TenderPublicController(TenderService tenderService, BidService bidService, CodeValueService codeValueService, - S3Wrapper s3Wrapper,ClarificationService clariSvc, CorrigendumService corrigendumService) { + public TenderPublicController(TenderService tenderService, ExternalTenderService externalTenderService + , BidService bidService, CodeValueService codeValueService, S3Wrapper s3Wrapper + , ClarificationService clariSvc, CorrigendumService corrigendumService + , TenderSubscriptionService tenderSubscriptionService, TenderItemService tenderItemService) { this.tenderService = tenderService; + this.externalTenderService = externalTenderService; this.bidService = bidService; this.codeValueService = codeValueService; this.s3Wrapper = s3Wrapper; this.clariSvc = clariSvc; this.corrigendumService = corrigendumService; + this.tenderSubscriptionService = tenderSubscriptionService; + this.tenderItemService = tenderItemService; } + /** + * This method is used for showing tender details screen. + * + * @param id unique identifier of the tender + * @param model ModelMap + * @param request HttpServletRequest + * @return String + */ @GetMapping("/tender/{id}") - public String showTenderDetails(@PathVariable(value="id") Integer id, ModelMap model) { + public String showTenderDetails(@PathVariable(value="id") Integer id, ModelMap model, HttpServletRequest request) { Tender tender = tenderService.findById(id); if (tender == null) { return "redirect:/"; } + + // Log visit statistic + try { + String remoteAddr; + + remoteAddr = request.getHeader("X-FORWARDED-FOR"); + if (remoteAddr == null || "".equals(remoteAddr)) { + remoteAddr = request.getRemoteAddr(); + } + + tenderService.logVisit(tender, remoteAddr); + } catch (Exception e) { + TTLogger.error(this.getClass().getName(), "Error when logging tender visit", e); + } + List lstClarification = clariSvc.findClarificationByTenderId(id); List lstCorrigendum = corrigendumService.findTenderCorrigendum(id); TenderClarificationDTO td = new TenderClarificationDTO(); Authentication auth = SecurityContextHolder.getContext().getAuthentication(); if (auth != null && !(auth instanceof AnonymousAuthenticationToken)) { CurrentUser usr = (CurrentUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); - TenderBookmark tenderBookmark = tenderService.findTenderBookmark(tender.getId(), usr.getId()); + TenderBookmark tenderBookmark = tenderSubscriptionService.findTenderBookmark(tender.getId(), usr.getId()); Bid bid = null; boolean isBookmarked; boolean isSubmitedTender; @@ -98,6 +146,15 @@ public String showTenderDetails(@PathVariable(value="id") Integer id, ModelMap m return "tenderDetails"; } + /** + * This method is used for showing tender response screen. + * + * @param id unique identifier of the tender + * @param request HttpServletRequest + * @param response HttpServletResponse + * @param model ModelMap + * @return String + */ @GetMapping("/tender/{id}/respond") public String showTenderResponsePage(@PathVariable(value = "id") Integer id, HttpServletRequest request, HttpServletResponse response, ModelMap model) { @@ -135,6 +192,20 @@ public String showTenderResponsePage(@PathVariable(value = "id") Integer id, Htt return "tenderResponse"; } + /** + * This method is used to save the tender response. + * This method can handle request both from normal HTTP and AJAX. + * This method will return the name of next screen or null for AJAX response. + * For AJAX response, this method will return the HTTP status and any error in the HTTP body. + * + * @param data input data of tender response + * @param request HttpServletRequest + * @param resp HttpServletResponse + * @param model ModelMap + * @return String + * @throws IOException if has exception when putting error message in AJAX response + * @see TenderResponseSubmitDTO + */ @PostMapping("/tender/respond") public String saveTenderResponse(@ModelAttribute("data") TenderResponseSubmitDTO data, HttpServletRequest request, HttpServletResponse resp, ModelMap model) throws IOException { @@ -153,7 +224,7 @@ public String saveTenderResponse(@ModelAttribute("data") TenderResponseSubmitDTO bid.setLastUpdatedDate(new Date()); for (TenderItemResponseSubmitDTO item : data.getItems()) { - TenderItem tenderItem = tenderService.findTenderItemById(item.getItemId()); + TenderItem tenderItem = tenderItemService.findTenderItemById(item.getItemId()); BidItem bidItem = new BidItem(); bidItem.setTenderItem(tenderItem); @@ -196,30 +267,48 @@ public String saveTenderResponse(@ModelAttribute("data") TenderResponseSubmitDTO } } + /** + * This method is used for bookmark tender. + * + * @param tenderId unique identifier of tender. + * @return String + */ @PostMapping("/tender/bookmark") public String bookmarkTender(@RequestParam("tenderId") int tenderId) { CurrentUser usr = (CurrentUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); Tender tender = tenderService.findById(tenderId); - tenderService.bookmarkTender(tender, usr.getUser()); + tenderSubscriptionService.bookmarkTender(tender, usr.getUser()); return "redirect:/tender/" + tenderId; } + /** + * This method is used for remove bookmark from tender. + * + * @param tenderId unique identifier of tender + * @return String + */ @PostMapping("/tender/removeBookmark") public String removeTenderBookmark(@RequestParam("tenderId") int tenderId) { CurrentUser usr = (CurrentUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); - tenderService.removeTenderBookmark(tenderId, usr.getUser().getId()); + tenderSubscriptionService.removeTenderBookmark(tenderId, usr.getUser().getId()); return "redirect:/tender/" + tenderId; } + /** + * This method is used to show subscribe tender category notification screen. + * + * @param model ModelMap + * @return String + */ @GetMapping("/tenderNotification") public String showSubscribeTenderCategoryNotification(ModelMap model) { CurrentUser usr = (CurrentUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); List tenderCategories = codeValueService.getAllTenderCategories(); - List currentSubscription = tenderService.findUserSubscription(usr.getId()); + List currentSubscription = tenderSubscriptionService.findUserSubscription(usr.getId()); List subscriptions = new LinkedList<>(); for (TenderCategorySubscription s : currentSubscription) { subscriptions.add(s.getTenderCategory().getId()); @@ -230,6 +319,13 @@ public String showSubscribeTenderCategoryNotification(ModelMap model) { return "tenderNotification"; } + /** + * This method is used to save tender category subscription. + * + * @param categories list of categories + * @param redirectAttrs RedirectAttributes + * @return String + */ @PostMapping("/tenderNotification") public String saveTenderCategorySubscription(@RequestParam("categories") List categories, RedirectAttributes redirectAttrs) { CurrentUser usr = (CurrentUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); @@ -239,7 +335,7 @@ public String saveTenderCategorySubscription(@RequestParam("categories") List pageSize @@ -293,7 +405,7 @@ public String showTenders(@RequestParam("pageSize") Optional pageSize Page tenders = tenderService.searchTender(dto , new PageRequest( - evalPage, evalPageSize, getSortPattern(dto) + evalPage, evalPageSize, getSortPattern(dto, false) )); Pager pager = new Pager(tenders.getTotalPages(), tenders.getNumber(), TTConstants.BUTTONS_TO_SHOW); @@ -310,7 +422,117 @@ evalPage, evalPageSize, getSortPattern(dto) return "home"; } - private Sort getSortPattern(TenderSearchDTO searchDTO) { + /** + * This method is used to show all external tenders. + * + * @param pageSize size per page + * @param page page number + * @param searchText search text + * @param title tender title search input + * @param companyName company name search input + * @param status tender status search input + * @param tenderSource tender source search input + * @param refNo tender reference no search input + * @param orderBy order by sorting input + * @param orderMode order mode asc / desc + * @param model ModelMap + * @return String + */ + @GetMapping("/external_tenders") + public String showExternalTenders(@RequestParam("pageSize") Optional pageSize + , @RequestParam("page") Optional page + , @RequestParam("searchText") Optional searchText + , @RequestParam("title") Optional title + , @RequestParam("companyName") Optional companyName + , @RequestParam("status") Optional status + , @RequestParam("tenderSource") Optional tenderSource + , @RequestParam("refNo") Optional refNo + , @RequestParam("orderBy") Optional orderBy + , @RequestParam("orderMode") Optional orderMode + , ModelMap model) { + // Evaluate page size. If requested parameter is null, return initial page size + TenderSearchDTO dto = new TenderSearchDTO(); + dto.setSearchText(searchText.orElse(null)); + dto.setTitle(title.orElse(null)); + dto.setCompanyName(companyName.orElse(null)); + if (status.orElse(0) > 0) { + dto.setEtStatus(TTCommonUtil.getExternalTenderStatus(status.orElse(0))); + } + dto.setTenderSource(tenderSource.orElse(0)); + dto.setRefNo(refNo.orElse(null)); + dto.setOrderBy(orderBy.orElse(null) == null? TTConstants.DEFAULT_SORT : orderBy.get()); + dto.setOrderMode(orderMode.orElse(null) == null? TTConstants.DEFAULT_SORT_DIRECTION : orderMode.get()); + dto.setAdvance(dto.getSearchText() != null || dto.getTitle() != null || dto.getCompanyName() != null + || dto.getEtStatus() != null || dto.getTenderSource() > 0 || dto.getRefNo() != null); + + int evalPageSize = pageSize.orElse(TTConstants.INITIAL_PAGE_SIZE); + // Evaluate page. If requested parameter is null or less than 0 (to + // prevent exception), return initial size. Otherwise, return value of + // param. decreased by 1. + int evalPage = (page.orElse(0) < 1) ? TTConstants.INITIAL_PAGE : page.get() - 1; + + Page externalTenders = externalTenderService.searchTender(dto + , new PageRequest( + evalPage, evalPageSize, getSortPattern(dto, true) + )); + Pager pager = new Pager(externalTenders.getTotalPages(), externalTenders.getNumber(), TTConstants.BUTTONS_TO_SHOW); + + model.addAttribute("external_tenders", externalTenders); + model.addAttribute("searchCriteria", dto); + model.addAttribute("codeValueSvc", codeValueService); + model.addAttribute("selectedPageSize", evalPageSize); + model.addAttribute("pager", pager); + if (externalTenders == null || externalTenders.getTotalPages() == 0) { + model.addAttribute("noTenderFound", true); + } else { + model.addAttribute("noTenderFound", false); + } + return "external_tenders"; + } + + /** + * This method use for custom redirect to GeBiz. + * This method will verify if the crawled URL is valid. If not, it will redirect to the alternate GeBiz URL. + * + * @param id unique identifier of tender + * @return String + */ + @GetMapping("/external_tenders/GeBiz/{id}") + public String redirectToGeBiz(@PathVariable(value = "id") Integer id) { + ExternalTender externalTender = externalTenderService.findByID(id); + + if (externalTender == null) { + return "redirect:/external_tenders"; + } + + String content; + URLConnection connection; + try { + connection = new URL("https://www.gebiz.gov.sg/ptn/opportunity/opportunityDetails.xhtml?code=" + externalTender.getReferenceNo()).openConnection(); + connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.4; en-US; rv:1.9.2.2) Gecko/20100316 Firefox/3.6.2"); + Scanner scanner = new Scanner(connection.getInputStream()); + scanner.useDelimiter("\\Z"); + content = scanner.next(); + if (content.contains("No opportunity found for your search") || content.contains("302")) { + return "redirect:https://www.gebiz.gov.sg/ptn/opportunityportal/opportunityDetails.xhtml?code=" + externalTender.getReferenceNo(); + } else { + return "redirect:https://www.gebiz.gov.sg/ptn/opportunity/opportunityDetails.xhtml?code=" + externalTender.getReferenceNo(); + } + }catch ( Exception ex ) { + TTLogger.error(this.getClass().getName(),"Error when redirecting to GeBiz", ex); + } + + return "redirect:" + externalTender.getTenderURL(); + } + + /** + * This method use to get sort pattern of the tenders screen and external tender screen. + * + * @param searchDTO TenderSearchDTO + * @param isExternal to check external tender or not + * @return Sort + */ + private Sort getSortPattern(TenderSearchDTO searchDTO, boolean isExternal) { Sort.Direction direction = Sort.Direction.ASC; // Set order direction. if (searchDTO.getOrderMode().equals(TTConstants.DESC)) { @@ -319,9 +541,17 @@ private Sort getSortPattern(TenderSearchDTO searchDTO) { // Set order by attribute. if (searchDTO.getOrderBy().equals(TTConstants.OPEN_DATE)) { - return new Sort(new Sort.Order(direction, TTConstants.OPEN_DATE)); + if (isExternal) { + return new Sort(new Sort.Order(direction, TTConstants.PUBLISHED_DATE)); + } else { + return new Sort(new Sort.Order(direction, TTConstants.OPEN_DATE)); + } } else if(searchDTO.getOrderBy().equals(TTConstants.CLOSED_DATE)) { - return new Sort(new Sort.Order(direction, TTConstants.CLOSED_DATE)); + if (isExternal) { + return new Sort(new Sort.Order(direction, TTConstants.CLOSING_DATE)); + } else { + return new Sort(new Sort.Order(direction, TTConstants.CLOSED_DATE)); + } } else { return new Sort(new Sort.Order(direction, TTConstants.TITLE)); } diff --git a/src/main/java/com/chlorocode/tendertracker/web/admin/AdminController.java b/src/main/java/com/chlorocode/tendertracker/web/admin/AdminController.java index cbf381f..407fa3e 100644 --- a/src/main/java/com/chlorocode/tendertracker/web/admin/AdminController.java +++ b/src/main/java/com/chlorocode/tendertracker/web/admin/AdminController.java @@ -9,16 +9,31 @@ import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; +/** + * Controller for admin dashboard page. + */ @Controller public class AdminController extends HttpServlet { - CompanyService companyService; + private CompanyService companyService; + /** + * Constructor + * + * @param companyService CompanyService + */ @Autowired public AdminController(CompanyService companyService) { this.companyService = companyService; } + /** + * This method is used for showing admin dashboard page. + * + * @param modelMap ModelMap + * @param request HttpServletRequest + * @return String + */ @GetMapping("/admin") public String showDashboardPage(ModelMap modelMap, HttpServletRequest request) { if (request.isUserInRole("ROLE_SYS_ADMIN")) { diff --git a/src/main/java/com/chlorocode/tendertracker/web/admin/BidController.java b/src/main/java/com/chlorocode/tendertracker/web/admin/BidController.java new file mode 100644 index 0000000..a03a219 --- /dev/null +++ b/src/main/java/com/chlorocode/tendertracker/web/admin/BidController.java @@ -0,0 +1,292 @@ +package com.chlorocode.tendertracker.web.admin; + +import com.chlorocode.tendertracker.dao.dto.AlertDTO; +import com.chlorocode.tendertracker.dao.dto.TenderItemResponseSubmitDTO; +import com.chlorocode.tendertracker.dao.dto.TenderResponseSubmitDTO; +import com.chlorocode.tendertracker.dao.entity.*; +import com.chlorocode.tendertracker.exception.ApplicationException; +import com.chlorocode.tendertracker.service.BidService; +import com.chlorocode.tendertracker.service.CodeValueService; +import com.chlorocode.tendertracker.service.TenderAppealService; +import com.chlorocode.tendertracker.service.TenderService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.servlet.mvc.support.RedirectAttributes; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.Date; + +/** + * Controller for admin bid related page. + */ +@Controller +public class BidController { + + private BidService bidService; + private TenderAppealService tenderAppealService; + private TenderService tenderService; + private CodeValueService codeValueService; + + /** + * Constructor. + * + * @param bidService BidService + * @param tenderAppealService TenderAppealService + * @param tenderService TenderService + * @param codeValueService CodeValueService + */ + @Autowired + public BidController(BidService bidService, TenderAppealService tenderAppealService + ,TenderService tenderService,CodeValueService codeValueService) { + this.bidService = bidService; + this.tenderAppealService = tenderAppealService; + this.tenderService = tenderService; + this.codeValueService = codeValueService; + } + + /** + * This method is used for showing list of bid submitted by the company. + * + * @return String + */ + @GetMapping("/admin/bid") + public String showSubmittedBidPage() { + return "admin/bid/bidView"; + } + + /** + * This method is used for showing submit tender appeal page. + * + * @param id unique identifier of the bid + * @param model ModelMap + * @return String + */ + @GetMapping("/admin/bid/appeal/{id}") + public String showTenderAppealPage(@PathVariable(value="id") Integer id, ModelMap model) { + Bid bid = bidService.findById(id); + + model.addAttribute("bid", bid); + + return "admin/bid/submitBidAppeal"; + } + + /** + * This method is used to save tender appeal. + * + * @param tenderId unique identifier of the tender + * @param reason appeal reason + * @param redirectAttrs RedirectAttributes + * @return String + */ + @PostMapping("/admin/bid/appeal/submit") + public String submitAppeal(@RequestParam("id") int tenderId, @RequestParam("reason") String reason, RedirectAttributes redirectAttrs){ + CurrentUser usr = (CurrentUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); + Company company = usr.getSelectedCompany(); + + TenderAppeal tender = new TenderAppeal(); + Tender td = new Tender(); + td.setId(tenderId); + + tender.setTender(td); + tender.setCompany(company); + tender.setReasons(reason); + tender.setCreatedBy(usr.getId()); + tender.setLastUpdatedBy(usr.getId()); + tender.setCreatedDate(new Date()); + tender.setLastUpdatedDate(new Date()); + + TenderAppeal result; + try { + result = tenderAppealService.create(tender); + } catch (ApplicationException ex) { + AlertDTO alert = new AlertDTO(AlertDTO.AlertType.DANGER, + ex.getMessage()); + redirectAttrs.addFlashAttribute("alert", alert); + return "redirect:/admin/bid" ; + } + + if(result != null){ + AlertDTO alert = new AlertDTO(AlertDTO.AlertType.SUCCESS, + "Appeal submitted successfully"); + redirectAttrs.addFlashAttribute("alert", alert); + }else{ + AlertDTO alert = new AlertDTO(AlertDTO.AlertType.DANGER, + "Not able to submit the appeal. Please contact Administrator"); + redirectAttrs.addFlashAttribute("alert", alert); + } + + return "redirect:/admin/bid" ; + } + + /** + * This method is used for showing list of submitted tender appeal to be processed by admin. + * + * @return String + */ + @GetMapping("/admin/tender/appeal") + public String showTenderAppealPage() { + return "admin/bid/tenderAppealList"; + } + + /** + * This method is used for showing process appeal page. + * + * @param id unique identifier of the tender appeal + * @param model ModelMap + * @return String + */ + @GetMapping("/admin/tender/appeal/view/{id}") + public String showTenderAppealUpdatePage(@PathVariable(value = "id") Integer id,ModelMap model) { + TenderAppeal tenderAppeal = tenderAppealService.findById(id); + + String status = ""; + if (tenderAppeal.getStatus() == 0) { + status = "Pending"; + } else if (tenderAppeal.getStatus() == 1) { + status = "Approved"; + } else if (tenderAppeal.getStatus() == 2) { + status = "Rejected"; + } + + model.addAttribute("bid", tenderAppeal); + model.addAttribute("status", status); + return "admin/bid/processAppealView"; + } + + /** + * This method is used for updating appeal status. + * + * @param id unique identifier of the tender appeal + * @param action action indicator whether approve / reject + * @param redirectAttrs RedirectAttributes + * @return String + */ + @PostMapping("/admin/bid/appeal/result") + public String processAppeal(@RequestParam("id") int id, @RequestParam("action") String action, + RedirectAttributes redirectAttrs) { + CurrentUser usr = (CurrentUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); + boolean result = false; + + if (action.equals("reject")) { + result = tenderAppealService.processTenderAppeal(id,usr.getId(),2); + } else if(action.equals("approve")) { + result = tenderAppealService.processTenderAppeal(id,usr.getId(),1); + } + + if (result) { + AlertDTO alert = new AlertDTO(AlertDTO.AlertType.SUCCESS, + "Tender appeal status updated successfully"); + redirectAttrs.addFlashAttribute("alert", alert); + } else { + AlertDTO alert = new AlertDTO(AlertDTO.AlertType.SUCCESS, + "Something went wrong. Cannot update tender process"); + redirectAttrs.addFlashAttribute("alert", alert); + } + + return "redirect:/admin/tender/appeal"; + } + + + /** + * This method is used for showing tender response screen. + * + * @param id unique identifier of the tender + * @param request HttpServletRequest + * @param response HttpServletResponse + * @param model ModelMap + * @return String + */ + @GetMapping("/admin/bid/amend/{id}") + public String amendBid(@PathVariable(value = "id") Integer id, HttpServletRequest request, + HttpServletResponse response, ModelMap model) { + // Check access right + if (!request.isUserInRole("ROLE_ADMIN") && !request.isUserInRole("ROLE_SUBMITTER")) { + response.setStatus(HttpServletResponse.SC_FORBIDDEN); + return null; + } + + // Check if tender exist + Tender tender = tenderService.findById(id); + if (tender == null) { + response.setStatus(HttpServletResponse.SC_NOT_FOUND); + return null; + } + + CurrentUser usr = (CurrentUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); + Company company = usr.getSelectedCompany(); + + TenderResponseSubmitDTO data = new TenderResponseSubmitDTO(); + for (TenderItem i : tender.getItems()) { + TenderItemResponseSubmitDTO itm = new TenderItemResponseSubmitDTO(); + itm.setItem(i); + itm.setItemId(i.getBidItems().get(0).getId()); + BidItem bidI = bidService.findBidItemById(i.getBidItems().get(0).getId()); + itm.setQuotedPrice(bidI.getAmount()); + + data.addTenderItem(itm); + } + + model.addAttribute("tender", tender); + model.addAttribute("company", company); + model.addAttribute("data", data); + model.addAttribute("codeValueService", codeValueService); + model.addAttribute("currency",codeValueService.getByType("currency")); + + return "admin/tender/amendBid"; + } + + /** + * This method is used to save the tender response. + * This method can handle request both from normal HTTP and AJAX. + * This method will return the name of next screen or null for AJAX response. + * For AJAX response, this method will return the HTTP status and any error in the HTTP body. + * + * @param data input data of tender response + * @param request HttpServletRequest + * @param resp HttpServletResponse + * @param model ModelMap + * @return String + * @throws IOException if has exception when putting error message in AJAX response + * @see TenderResponseSubmitDTO + */ + @PostMapping("/tender/respond/amend") + public String AmendTenderResponse(@ModelAttribute("data") TenderResponseSubmitDTO data, HttpServletRequest request, + HttpServletResponse resp, ModelMap model) throws IOException { + + Tender tender = tenderService.findById(data.getTenderId()); + CurrentUser usr = (CurrentUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); + + try + { + for (TenderItemResponseSubmitDTO item : data.getItems()) { + BidItem bidItem = bidService.findBidItemById(item.getItemId()); + bidItem.setAmount(item.getQuotedPrice()); + bidItem.setCreatedBy(usr.getId()); + bidItem.setCreatedDate(new Date()); + bidItem.setLastUpdatedBy(usr.getId()); + bidItem.setLastUpdatedDate(new Date()); + bidItem.setCurrency(item.getCurrency()); + bidService.updateBid(bidItem); + AlertDTO alert = new AlertDTO(AlertDTO.AlertType.SUCCESS, + "Tender appeal status updated successfully"); + model.addAttribute("alert", alert); + // bid.addBidItem(bidItem); + } + } catch(ApplicationException ex) { + AlertDTO alert = new AlertDTO(AlertDTO.AlertType.DANGER, + ex.getMessage()); + model.addAttribute("alert", alert); + model.addAttribute("tender", tender); + model.addAttribute("company", usr.getSelectedCompany()); + model.addAttribute("data", data); + model.addAttribute("codeValueService", codeValueService); + } + + return "redirect:/admin/bid"; + } +} diff --git a/src/main/java/com/chlorocode/tendertracker/web/admin/CompanyAdminController.java b/src/main/java/com/chlorocode/tendertracker/web/admin/CompanyAdminController.java index 1fc6012..6bad443 100644 --- a/src/main/java/com/chlorocode/tendertracker/web/admin/CompanyAdminController.java +++ b/src/main/java/com/chlorocode/tendertracker/web/admin/CompanyAdminController.java @@ -23,18 +23,33 @@ import javax.validation.Valid; import java.util.Date; +/** + * Controller for company profile management page in admin portal. + */ @Controller public class CompanyAdminController { private CompanyService companyService; private CodeValueService codeValueService; + /** + * Constructor. + * + * @param companyService CompanyService + * @param codeValueService CodeValueService + */ @Autowired public CompanyAdminController(CompanyService companyService, CodeValueService codeValueService) { this.companyService = companyService; this.codeValueService = codeValueService; } + /** + * This method is used to display company profile page for the current company managed by logged in user. + * + * @param model Model Map + * @return String + */ @GetMapping("/admin/company") public String showCompanyInfoPage(ModelMap model) { CurrentUser usr = (CurrentUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); @@ -55,6 +70,15 @@ protected void configure() { return "admin/company/companyInfo"; } + /** + * This method is used to update company profile. + * + * @param form form data wrapped in CompanyInfoDTO + * @param model ModelMap + * @param result to check form binding error + * @param redirectAttrs RedirectAttributes + * @return String + */ @PostMapping("/admin/company") public String updateCompanyInfo(@Valid @ModelAttribute("company") CompanyInfoDTO form, ModelMap model, BindingResult result, RedirectAttributes redirectAttrs) { diff --git a/src/main/java/com/chlorocode/tendertracker/web/admin/CompanyUserController.java b/src/main/java/com/chlorocode/tendertracker/web/admin/CompanyUserController.java index ce2f087..4c5b396 100644 --- a/src/main/java/com/chlorocode/tendertracker/web/admin/CompanyUserController.java +++ b/src/main/java/com/chlorocode/tendertracker/web/admin/CompanyUserController.java @@ -20,23 +20,43 @@ import java.util.List; import java.util.Optional; +/** + * Controller for company user management page in admin portal. + */ @Controller public class CompanyUserController { private UserRoleService userRoleService; private UserService userService; + /** + * Constructor. + * + * @param userRoleService UserRoleService + * @param userService UserService + */ @Autowired public CompanyUserController(UserRoleService userRoleService, UserService userService) { this.userRoleService = userRoleService; this.userService = userService; } + /** + * This method is used to display page to list company user. + * + * @return String + */ @GetMapping("/admin/companyUser") public String showCompanyUserList() { return "admin/user/userList"; } + /** + * This method is used to display add company user page. + * + * @param model ModelMap + * @return String + */ @GetMapping("/admin/companyUser/add") public String showAddUserPage(ModelMap model) { model.addAttribute("form", new CompanyUserAddDTO()); @@ -44,6 +64,15 @@ public String showAddUserPage(ModelMap model) { return "admin/user/userAdd"; } + /** + * This method is used to save new company user. + * + * @param form data inputted by user + * @param model ModelMap + * @param redirectAttrs RedirectAttributes + * @return String + * @see CompanyUserAddDTO + */ @PostMapping("/admin/companyUser/add") public String addCompanyUser(@Valid @ModelAttribute("form") CompanyUserAddDTO form, ModelMap model, RedirectAttributes redirectAttrs) { @@ -86,6 +115,13 @@ public String addCompanyUser(@Valid @ModelAttribute("form") CompanyUserAddDTO fo return "redirect:/admin/companyUser"; } + /** + * This method is used to display company user details page. + * + * @param id unique identifier of the user + * @param model ModelMap + * @return String + */ @GetMapping("/admin/companyUser/{id}") public String showCompanyUserDetails(@PathVariable(value="id") int id, ModelMap model) { User usr = userService.findById(id); @@ -109,6 +145,14 @@ public String showCompanyUserDetails(@PathVariable(value="id") int id, ModelMap return "admin/user/updateUserRole"; } + /** + * This method is used to update company user details. + * + * @param roles new list roles to replace existing roles + * @param userId unique identifier of the user + * @param redirectAttrs RedirectAttributes + * @return String + */ @PostMapping("/admin/companyUser/update") public String editCompanyUser(@RequestParam("roles") List roles, @RequestParam("userId") int userId, RedirectAttributes redirectAttrs) { @@ -128,6 +172,13 @@ public String editCompanyUser(@RequestParam("roles") List roles, @Reque return "redirect:/admin/companyUser"; } + /** + * This method is used to remove company user. + * + * @param userId unique identifier of the user + * @param redirectAttrs RedirectAttributes + * @return String + */ @PostMapping("/admin/companyUser/remove") public String removeCompanyUser(@RequestParam("id") int userId, RedirectAttributes redirectAttrs) { User usr = userService.findById(userId); diff --git a/src/main/java/com/chlorocode/tendertracker/web/admin/CorrigendumController.java b/src/main/java/com/chlorocode/tendertracker/web/admin/CorrigendumController.java index f74e16a..6a563d4 100644 --- a/src/main/java/com/chlorocode/tendertracker/web/admin/CorrigendumController.java +++ b/src/main/java/com/chlorocode/tendertracker/web/admin/CorrigendumController.java @@ -25,6 +25,9 @@ import java.io.IOException; import java.util.Date; +/** + * Controller for tender corrigendum page in admin portal. + */ @Controller public class CorrigendumController { @@ -33,6 +36,14 @@ public class CorrigendumController { private CodeValueService codeValueService; private S3Wrapper s3Service; + /** + * Constructor. + * + * @param corrigendumService CorrigendumService + * @param tenderService TenderService + * @param codeValueService CodeValueService + * @param s3Service S3Wrapper + */ @Autowired public CorrigendumController(CorrigendumService corrigendumService, TenderService tenderService, CodeValueService codeValueService, S3Wrapper s3Service) { @@ -42,6 +53,13 @@ public CorrigendumController(CorrigendumService corrigendumService, TenderServic this.s3Service = s3Service; } + /** + * This method is used to show list of corrigendum for a particular tender. + * + * @param id unique identifier of the tender + * @param model ModelMap + * @return String + */ @GetMapping("/admin/tender/{id}/corrigendum") public String showTenderCorrigendum(@PathVariable(value = "id") int id, ModelMap model) { Tender tender = tenderService.findById(id); @@ -56,6 +74,13 @@ public String showTenderCorrigendum(@PathVariable(value = "id") int id, ModelMap return "admin/corrigendum/corrigendumList"; } + /** + * This method is used to display add corrigendum page. + * + * @param id unique identifier of the tender + * @param model ModelMap + * @return String + */ @GetMapping("/admin/tender/{id}/addCorrigendum") public String showAddCorrigendumPage(@PathVariable(value = "id") int id, ModelMap model) { Tender tender = tenderService.findById(id); @@ -72,9 +97,25 @@ public String showAddCorrigendumPage(@PathVariable(value = "id") int id, ModelMa return "admin/corrigendum/corrigendumAdd"; } + /** + * This method is used to create new corrigendum. + * This method can handle request both from normal HTTP and AJAX. + * This method will return the name of next screen or null for AJAX response. + * For AJAX response, this method will return the HTTP status and any error in the HTTP body. + * + * @param form corrigendum data inputted by user + * @param result this result is used to validate DTO binding validation result + * @param model ModelMap + * @param request HttpServletRequest + * @param resp HttpServletResponse + * @return String + * @throws IOException if has exception when putting error message in AJAX response + * @see CorrigendumCreateDTO + * + */ @PostMapping("/admin/tender/addCorrigendum") - public String saveCorrigendum(@Valid @ModelAttribute("corrigendum") CorrigendumCreateDTO form, BindingResult result, - RedirectAttributes redirectAttrs, ModelMap model, HttpServletRequest request, + public String saveCorrigendum(@Valid @ModelAttribute("corrigendum") CorrigendumCreateDTO form, + BindingResult result, ModelMap model, HttpServletRequest request, HttpServletResponse resp) throws IOException { String requestedWith = request.getHeader("X-Requested-With"); Boolean isAjax = requestedWith != null && "XMLHttpRequest".equals(requestedWith); @@ -115,6 +156,14 @@ public String saveCorrigendum(@Valid @ModelAttribute("corrigendum") CorrigendumC } } + /** + * This method is used to remove corrigendum. + * + * @param corrigendumId unique identifier of the corrigendum + * @param tenderId unique identifier of the tender + * @param redirectAttrs RedirectAttributes + * @return String + */ @PostMapping("/admin/tender/removeCorrigendum") public String removeCorrigendum(@RequestParam("corrigendumId") int corrigendumId, @RequestParam("tenderId") int tenderId, RedirectAttributes redirectAttrs) { @@ -125,6 +174,13 @@ public String removeCorrigendum(@RequestParam("corrigendumId") int corrigendumId return "redirect:/admin/tender/" + tenderId + "/corrigendum"; } + /** + * This method is used to display edit corrigendum page. + * + * @param id unique identififer of the corrigendum + * @param model ModelMap + * @return String + */ @GetMapping("/admin/tender/corrigendum/{id}/edit") public String showEditCorrigendumPage(@PathVariable(value = "id") int id, ModelMap model) { Corrigendum corrigendum = corrigendumService.findCorrigendumById(id); @@ -144,6 +200,16 @@ public String showEditCorrigendumPage(@PathVariable(value = "id") int id, ModelM return "admin/corrigendum/corrigendumEdit"; } + /** + * This method is used to edit corrigendum. + * + * @param form corrigendum data inputted by user + * @param result this result is used to validate DTO binding validation result + * @param model ModelMap + * @param redirectAttrs RedirectAttributes + * @return String + * @see CorrigendumUpdateDTO + */ @PostMapping("/admin/tender/editCorrigendum") public String editCorrigendum(@Valid @ModelAttribute("corrigendum") CorrigendumUpdateDTO form, BindingResult result, ModelMap model, RedirectAttributes redirectAttrs) { @@ -172,6 +238,15 @@ public String editCorrigendum(@Valid @ModelAttribute("corrigendum") CorrigendumU return "redirect:/admin/tender/" + corrigendum.getTender().getId() + "/corrigendum"; } + /** + * This method is used to add new document to a corrigendum via AJAX. + * + * @param files document to be added + * @param corrigendumId unique identifier of the corrigendum + * @param resp HttpServletResponse + * @return String + * @throws IOException if unable to write error message into response body + */ @PostMapping("/admin/tender/addCorrigendumDocument") public String addCorrigendumDocument(@RequestParam(name = "file") MultipartFile files, @RequestParam(name = "id") int corrigendumId, @@ -194,6 +269,14 @@ public String addCorrigendumDocument(@RequestParam(name = "file") MultipartFile } } + /** + * This method is used to remove a document from a corrigendum. + * + * @param documentId unique identifier of the document + * @param corrigendumId unique identifier of the corrigendum + * @param redirectAttrs RedirectAttributes + * @return String + */ @PostMapping("/tender/removeCorrigendumDocument") public String removeCorrigendumDocument(@RequestParam(name = "corrigendumDocumentId") int documentId, @RequestParam(name = "corrigendumId") int corrigendumId, diff --git a/src/main/java/com/chlorocode/tendertracker/web/admin/EvaluationCriteriaController.java b/src/main/java/com/chlorocode/tendertracker/web/admin/EvaluationCriteriaController.java index c8f2529..48107b0 100644 --- a/src/main/java/com/chlorocode/tendertracker/web/admin/EvaluationCriteriaController.java +++ b/src/main/java/com/chlorocode/tendertracker/web/admin/EvaluationCriteriaController.java @@ -5,7 +5,6 @@ import com.chlorocode.tendertracker.dao.entity.CurrentUser; import com.chlorocode.tendertracker.dao.entity.EvaluationCriteria; import com.chlorocode.tendertracker.dao.entity.Tender; -import com.chlorocode.tendertracker.exception.ApplicationException; import com.chlorocode.tendertracker.logging.TTLogger; import com.chlorocode.tendertracker.service.CodeValueService; import com.chlorocode.tendertracker.service.EvaluationService; @@ -26,7 +25,7 @@ import java.util.List; /** - * Created by andy on 3/8/2017. + * Controller for tender evaluation criteria in admin portal. */ @Controller public class EvaluationCriteriaController { @@ -36,6 +35,13 @@ public class EvaluationCriteriaController { private EvaluationService evaSvc; private String className; + /** + * Constructor. + * + * @param codeValueService CodeValueService + * @param evaSvc EvaluationService + * @param tenderService TenderService + */ @Autowired public EvaluationCriteriaController(CodeValueService codeValueService, EvaluationService evaSvc, TenderService tenderService) { @@ -45,6 +51,13 @@ public EvaluationCriteriaController(CodeValueService codeValueService, Evaluatio this.className = this.getClass().getName(); } + /** + * This method is used to display all evaluation criteria for a particular tender. + * + * @param tenderId unique identifier of the tender + * @param model ModelMap + * @return String + */ @GetMapping("/admin/tender/{tenderid}/setcriteria") public String showTenderEvaluationCriteriaPage(@PathVariable(value="tenderid") int tenderId, ModelMap model) { @@ -76,6 +89,14 @@ public String showTenderEvaluationCriteriaPage(@PathVariable(value="tenderid") i return "admin/tender/tenderEvaluationCriteria"; } + /** + * This method is used add a new evaluation criteria. + * + * @param form input data from user + * @param redirectAttrs RedirectAttributes + * @return String + * @see EvaluateCriteriaDTO + */ @PostMapping("/admin/tender/criteria/save") public String addTenderCriteria(@Valid EvaluateCriteriaDTO form, RedirectAttributes redirectAttrs) { TTLogger.info(className, "Adding new Tender Evaluation Criteria tenderId:" + form.getTenderId() + ", type: " + form.getType() + ", desc: " + form.getDescription()); @@ -106,6 +127,15 @@ public String addTenderCriteria(@Valid EvaluateCriteriaDTO form, RedirectAttribu return "redirect:/admin/tender/" + form.getTenderId() + "/setcriteria"; } + /** + * This method is used to update / delete evaluation criteria. + * + * @param form input data from user + * @param redirectAttrs RedirectAttributes + * @param action update / delete indicator for the action to be performed + * @return String + * @see EvaluateCriteriaDTO + */ @PostMapping("/admin/tender/criteria/update") public String updateTenderCriteria(@Valid EvaluateCriteriaDTO form, RedirectAttributes redirectAttrs, @RequestParam("action") String action) { diff --git a/src/main/java/com/chlorocode/tendertracker/web/admin/MilestoneController.java b/src/main/java/com/chlorocode/tendertracker/web/admin/MilestoneController.java new file mode 100644 index 0000000..53e7369 --- /dev/null +++ b/src/main/java/com/chlorocode/tendertracker/web/admin/MilestoneController.java @@ -0,0 +1,216 @@ +package com.chlorocode.tendertracker.web.admin; + +import com.chlorocode.tendertracker.dao.dto.AlertDTO; +import com.chlorocode.tendertracker.dao.dto.MilestoneDTO; +import com.chlorocode.tendertracker.dao.entity.CurrentUser; +import com.chlorocode.tendertracker.dao.entity.Milestone; +import com.chlorocode.tendertracker.dao.entity.Tender; +import com.chlorocode.tendertracker.logging.TTLogger; +import com.chlorocode.tendertracker.service.CodeValueService; +import com.chlorocode.tendertracker.service.MilestoneService; +import com.chlorocode.tendertracker.service.TenderService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.WebDataBinder; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.servlet.mvc.support.RedirectAttributes; + +import javax.validation.Valid; +import java.beans.PropertyEditorSupport; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.LinkedList; +import java.util.List; + +/** + * Controller for tender milestone page in admin portal. + */ +@Controller +public class MilestoneController { + + private CodeValueService codeValueService; + private TenderService tenderService; + private MilestoneService milestoneService; + private String className; + + /** + * Constructor. + * + * @param codeValueService CodeValueService + * @param milestoneService MilestoneService + * @param tenderService TenderService + */ + @Autowired + public MilestoneController(CodeValueService codeValueService, MilestoneService milestoneService, TenderService tenderService) + { + this.codeValueService = codeValueService; + this.milestoneService = milestoneService; + this.tenderService = tenderService; + this.className = this.getClass().getName(); + } + + /** + * This method is used to display tender milestone list page. + * + * @param tenderId unique identifier of the tender + * @param model ModelMap + * @return String + */ + @GetMapping("/admin/tender/{tenderid}/setmilestone") + public String showTenderMilestonePage(@PathVariable(value="tenderid") int tenderId, ModelMap model) + { + Tender tender = tenderService.findById(tenderId); + if (tender == null) { + TTLogger.error(className, "Unable to find tender, tenderID: " + tenderId); + return "redirect:/admin/tender"; + } + + model.addAttribute("statusList", codeValueService.getByType("milestone_status")); + List milestones = milestoneService.findMilestoneByTender(tenderId); + + List dto = new LinkedList<>(); + if (milestones != null) { + for (Milestone c : milestones) { + MilestoneDTO milestoneDTO = new MilestoneDTO(); + milestoneDTO.setId(c.getId()); + milestoneDTO.setTenderId(c.getTender().getId()); + milestoneDTO.setStatus(c.getStatus()); + milestoneDTO.setDueDate(c.getDueDate()); + milestoneDTO.setDescription(c.getDescription()); + dto.add(milestoneDTO); + } + } + model.addAttribute("tender", tender); + model.addAttribute("milestones", dto); + model.addAttribute("newMilestone", new MilestoneDTO()); + model.addAttribute("tenderId", tenderId); + model.addAttribute("dateFormat", dateFormat()); + return "admin/tender/tenderMilestone"; + } + + /** + * This method is used to add new tender milestone. + * + * @param form milestone data inputted by user + * @param redirectAttrs RedirectAttributes + * @return String + * @see MilestoneDTO + */ + @PostMapping("/admin/tender/milestone/save") + public String addMilestone(@Valid @ModelAttribute("newMilestone") MilestoneDTO form, RedirectAttributes redirectAttrs) { + TTLogger.info(className, "Adding new Tender Milestone tenderId:" + form.getTenderId() + ", status: " + form.getStatus() + ", desc: " + form.getDescription()); + + Tender tender = tenderService.findById(form.getTenderId()); + if (tender == null) { + TTLogger.error(className, "Unable to find tender, tenderID: " + form.getTenderId()); + return "redirect:/admin/tender"; + } + + CurrentUser usr = (CurrentUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); + + Milestone milestone = new Milestone(); + milestone.setTender(tender); + milestone.setNotifyStatus(0); + milestone.setStatus(form.getStatus()); + milestone.setDueDate(form.getDueDate()); + milestone.setDescription(form.getDescription()); + milestone.setCreatedBy(usr.getId()); + milestone.setCreatedDate(new Date()); + milestone.setLastUpdatedBy(usr.getId()); + milestone.setLastUpdatedDate(new Date()); + + milestoneService.create(milestone); + + TTLogger.info(className, "Tender Milestone Added="+milestone); + + AlertDTO alert = new AlertDTO(AlertDTO.AlertType.SUCCESS, "Milestone Created"); + redirectAttrs.addFlashAttribute("alert", alert); + return "redirect:/admin/tender/" + form.getTenderId() + "/setmilestone"; + } + + /** + * This method is used to update / delete tender milestone. + * + * @param form milestone data inputted by user + * @param redirectAttrs RedirectAttributes + * @param action update / delete indicator for the action to be performed + * @return String + * @see MilestoneDTO + */ + @PostMapping("/admin/tender/milestone/update") + public String updateMilestone(@Valid MilestoneDTO form, RedirectAttributes redirectAttrs, + @RequestParam("action") String action) { + if (action.equals("update")) { + TTLogger.info(className, "Update Tender Milestone evalId:" + form.getId() + ", status: " + form.getStatus() + ", desc: " + form.getDescription()); + + Milestone milestone = milestoneService.findMilestoneById(form.getId()); + if (milestone == null) { + TTLogger.error(className, "Unable to find Milestone, milestoneId: " + form.getId()); + return "redirect:/admin/tender"; + } + + CurrentUser usr = (CurrentUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); + + milestone.setStatus(form.getStatus()); + if (!milestone.getDueDate().equals(form.getDueDate())) { + // Reset notify status to resend notification for milestone. + milestone.setNotifyStatus(0); + } + milestone.setDueDate(form.getDueDate()); + milestone.setDescription(form.getDescription()); + milestone.setLastUpdatedBy(usr.getId()); + milestone.setLastUpdatedDate(new Date()); + + milestoneService.update(milestone); + + TTLogger.info(className, "Tender Milestone Updated"); + + AlertDTO alert = new AlertDTO(AlertDTO.AlertType.SUCCESS, "Milestone Updated"); + redirectAttrs.addFlashAttribute("alert", alert); + return "redirect:/admin/tender/" + form.getTenderId() + "/setmilestone"; + } else if (action.equals("delete")) { + TTLogger.info(className, "Delete Tender Milestone milestoneId:" + form.getId()); + + milestoneService.removeMilestone(form.getId()); + + TTLogger.info(className, "Tender Milestone Removed"); + + AlertDTO alert = new AlertDTO(AlertDTO.AlertType.SUCCESS, "Milestone Removed"); + redirectAttrs.addFlashAttribute("alert", alert); + } + return "redirect:/admin/tender/" + form.getTenderId() + "/setmilestone"; + } + + @InitBinder + public void binder(WebDataBinder binder) { + binder.registerCustomEditor(Date.class, new PropertyEditorSupport() { + public void setAsText(String value) { + try { + setValue(new SimpleDateFormat("dd/MM/yyyy HH:mm").parse(value)); + } catch(ParseException e) { + try { + setValue(new SimpleDateFormat("dd/MM/yyyy").parse(value)); + } catch(ParseException e2) { + setValue(null); + } + } + } + + public String getAsText() { + if (getValue() == null) { + return ""; + } else { + return new SimpleDateFormat("dd/MM/yyyy HH:mm").format((Date) getValue()); + } + } + }); + } + + @ModelAttribute("dateFormat") + public String dateFormat() { + return "dd/MM/yyyy HH:mm"; + } +} diff --git a/src/main/java/com/chlorocode/tendertracker/web/admin/ProductController.java b/src/main/java/com/chlorocode/tendertracker/web/admin/ProductController.java new file mode 100644 index 0000000..1e4e74f --- /dev/null +++ b/src/main/java/com/chlorocode/tendertracker/web/admin/ProductController.java @@ -0,0 +1,196 @@ +package com.chlorocode.tendertracker.web.admin; + +import com.chlorocode.tendertracker.dao.dto.AlertDTO; +import com.chlorocode.tendertracker.dao.dto.ProductCreateDTO; +import com.chlorocode.tendertracker.dao.dto.ProductUpdateDTO; +import com.chlorocode.tendertracker.dao.entity.Company; +import com.chlorocode.tendertracker.dao.entity.CurrentUser; +import com.chlorocode.tendertracker.dao.entity.Product; +import com.chlorocode.tendertracker.exception.ApplicationException; +import com.chlorocode.tendertracker.service.CodeValueService; +import com.chlorocode.tendertracker.service.CompanyService; +import com.chlorocode.tendertracker.service.ProductService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.servlet.mvc.support.RedirectAttributes; + +import javax.validation.Valid; +import java.util.Date; + +/** + * Controller for marketplace product page in admin portal. + */ +@Controller +public class ProductController { + + private ProductService productService; + private CodeValueService codeValueService; + private CompanyService companyService; + + /** + * Constructor. + * + * @param productService ProductService + * @param codeValueService CodeValueService + * @param companyService CompanyService + */ + @Autowired + public ProductController(ProductService productService, CodeValueService codeValueService, + CompanyService companyService) { + this.productService = productService; + this.codeValueService = codeValueService; + this.companyService = companyService; + } + + /** + * This method is used to display product list page. + * + * @return String + */ + @GetMapping("/admin/product") + public String showProductPage() { + return "admin/product/productView"; + } + + /** + * This method is used to display create product page. + * + * @param model ModelMap + * @param redirectAttrs RedirectAttributes + * @return String + */ + @GetMapping("/admin/product/create") + public String showCreateProductPage(ModelMap model, RedirectAttributes redirectAttrs) { + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + CurrentUser currentUser = (CurrentUser) authentication.getPrincipal(); + Company curentCompany = companyService.findById(currentUser.getSelectedCompany().getId()); + + // Check if current company is blacklisted + if (!curentCompany.isActive()) { + AlertDTO alertDTO = new AlertDTO(AlertDTO.AlertType.DANGER, "Your company is blacklisted. You are not allowed to add new product."); + redirectAttrs.addFlashAttribute("alert", alertDTO); + return "redirect:/admin/product"; + } + + model.addAttribute("product", new ProductCreateDTO()); + model.addAttribute("productCategory", codeValueService.getByType("product_category")); + return "admin/product/productCreate"; + } + + /** + * This method is used to save new marketplace product. + * + * @param form input data by user + * @param redirectAttributes RedirectAttributes + * @param modelMap ModelMap + * @return String + * @see ProductCreateDTO + */ + @PostMapping("/admin/product/create") + public String saveCreatedProduct(@Valid @ModelAttribute("product") ProductCreateDTO form, RedirectAttributes redirectAttributes, + ModelMap modelMap) { + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + CurrentUser currentUser = (CurrentUser) authentication.getPrincipal(); + + Product product = new Product(); + product.setTitle(form.getTitle()); + product.setPrice(form.getPrice()); + product.setDescription(form.getDescription()); + product.setCompany(currentUser.getSelectedCompany()); + product.setType(form.getType()); + product.setCategory(form.getCategory()); + product.setPublish(true); + product.setCreatedBy(currentUser.getId()); + product.setCreatedDate(new Date()); + product.setLastUpdatedBy(currentUser.getId()); + product.setLastUpdatedDate(new Date()); + + try { + productService.createProduct(product); + + AlertDTO alertDTO = new AlertDTO(AlertDTO.AlertType.SUCCESS, "Product Created"); + redirectAttributes.addFlashAttribute("alert", alertDTO); + } catch (ApplicationException exception) { + AlertDTO alertDTO = new AlertDTO(AlertDTO.AlertType.DANGER, exception.getMessage()); + modelMap.addAttribute("alert", alertDTO); + modelMap.addAttribute("product", form); + return "admin/product/create"; + } + + return "redirect:/admin/product"; + } + + /** + * This method is used to display edit product page. + * + * @param id unique identifier of the product + * @param model ModelMap + * @return String + */ + @GetMapping("/admin/product/{id}") + public String showProductEditPage(@PathVariable(value = "id") Integer id, ModelMap model) { + Product product = productService.findById(id); + if (product == null) { + return "redirect:/admin/product"; + } + + ProductUpdateDTO productDTO = new ProductUpdateDTO(); + productDTO.setProductCode(product.getProductCode()); + productDTO.setCategory(product.getCategory()); + productDTO.setDescription(product.getDescription()); + productDTO.setPrice(product.getPrice()); + productDTO.setTitle(product.getTitle()); + productDTO.setType(product.getType()); + productDTO.setPublished(product.isPublish()); + + model.addAttribute("product", productDTO); + model.addAttribute("productCategory", codeValueService.getByType("product_category")); + + return "admin/product/productUpdate"; + } + + /** + * This method is used to update product. + * + * @param form input data from user + * @param redirectAttrs RedirectAttributes + * @return String + * @see ProductUpdateDTO + */ + @PostMapping("/admin/product/update") + public String updateProduct(@Valid @ModelAttribute("product") ProductUpdateDTO form, RedirectAttributes redirectAttrs) { + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + CurrentUser currentUser = (CurrentUser) authentication.getPrincipal(); + + Product product = productService.findById(form.getProductCode()); + + product.setType(form.getType()); + product.setCategory(form.getCategory()); + product.setTitle(form.getTitle()); + product.setDescription(form.getDescription()); + product.setPublish(form.isPublished()); + product.setPrice(form.getPrice()); + product.setLastUpdatedBy(currentUser.getId()); + product.setLastUpdatedDate(new Date()); + + try { + productService.updateProduct(product); + } catch (ApplicationException ex) { + AlertDTO alert = new AlertDTO(AlertDTO.AlertType.DANGER, + ex.getMessage()); + redirectAttrs.addFlashAttribute("alert", alert); + return "redirect:/admin/product/" + form.getProductCode(); + } + + AlertDTO alert = new AlertDTO(AlertDTO.AlertType.SUCCESS, "Product Updated"); + redirectAttrs.addFlashAttribute("alert", alert); + return "redirect:/admin/product"; + } +} diff --git a/src/main/java/com/chlorocode/tendertracker/web/admin/TenderAwardController.java b/src/main/java/com/chlorocode/tendertracker/web/admin/TenderAwardController.java new file mode 100644 index 0000000..c957836 --- /dev/null +++ b/src/main/java/com/chlorocode/tendertracker/web/admin/TenderAwardController.java @@ -0,0 +1,148 @@ +package com.chlorocode.tendertracker.web.admin; + +import com.chlorocode.tendertracker.dao.dto.AlertDTO; +import com.chlorocode.tendertracker.dao.entity.*; +import com.chlorocode.tendertracker.service.BidService; +import com.chlorocode.tendertracker.service.EvaluationService; +import com.chlorocode.tendertracker.service.TenderService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.context.request.WebRequest; +import org.springframework.web.servlet.mvc.support.RedirectAttributes; + +import java.util.Date; +import java.util.List; + +/** + * Controller for tender award page in admin portal. + */ +@Controller +public class TenderAwardController { + + private TenderService tenderService; + private BidService bidService; + private EvaluationService evaluationService; + + /** + * Constructor. + * + * @param tenderService TenderService + * @param bidService BidService + * @param evaluationService EvaluationService + */ + @Autowired + public TenderAwardController(TenderService tenderService, BidService bidService, EvaluationService evaluationService) { + this.tenderService = tenderService; + this.bidService = bidService; + this.evaluationService = evaluationService; + } + + /** + * This method is used to display page containing the list of tenders to be awarded. + * + * @return String + */ + @GetMapping("/admin/tender/award") + public String showTenderAwardListPage() { + return "admin/tender/tenderAwardList"; + } + + /** + * This method is used to display award tender page. + * + * @param id unique identifier of the tender + * @param model ModelMap + * @return String + */ + @GetMapping("/admin/tender/award/{id}") + public String showTenderAwardPage(@PathVariable(value="id") Integer id, ModelMap model) { + Tender tender = tenderService.findById(id); + + List criteria = evaluationService.findEvaluationCriteriaByTender(id); + String criteriaList = ""; + for (EvaluationCriteria c : criteria) { + criteriaList += c.getId() + ","; + } + if (criteriaList.length() > 0) { + criteriaList = criteriaList.substring(0, criteriaList.length() - 1); + } + + + model.addAttribute("tender", tender); + model.addAttribute("evaluationCriteria", criteria); + model.addAttribute("evaluationCriteraList", criteriaList); + + return "admin/tender/tenderAward"; + } + + /** + * This method is used to update the tender as no award if no company bid on that. + * + * @param id unique identifier of the tender + * @param model ModelMap + * @param redirectAttrs RedirectAttributes + * @return String + */ + @GetMapping("/admin/tender/noawarded/{id}") + public String setNoAwardTender(@PathVariable(value="id") Integer id, ModelMap model, RedirectAttributes redirectAttrs) { + Tender tender = tenderService.findById(id); + CurrentUser usr = (CurrentUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); + tender.setStatus(4); + tender.setLastUpdatedBy(usr.getId()); + tender.setLastUpdatedDate(new Date()); + + try { + tenderService.updateTender(tender); + } catch (Exception ex) { + AlertDTO alert = new AlertDTO(AlertDTO.AlertType.DANGER, + ex.getMessage()); + redirectAttrs.addFlashAttribute("alert", alert); + return "redirect:/admin/tender/award/" + id; + } + + AlertDTO alert = new AlertDTO(AlertDTO.AlertType.SUCCESS, "Tender updated to no award"); + redirectAttrs.addFlashAttribute("alert", alert); + return "redirect:/admin/tender/award"; + } + /** + * This method is used to save tender award. + * + * @param id unique identifier of the bid + * @param request WebRequest + * @param redirectAttrs RedirectAttributes + * @return String + */ + @PostMapping("/admin/tender/award/{id}") + public String saveTenderAward(@PathVariable(value="id") Integer id, WebRequest request, RedirectAttributes redirectAttrs) { + CurrentUser usr = (CurrentUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); + + Bid bid = bidService.findById(Integer.parseInt(request.getParameter("awardTo"))); + + TenderAward tenderAward = new TenderAward(); + tenderAward.setBid(bid); + tenderAward.setTender(bid.getTender()); + tenderAward.setCompany(bid.getCompany()); + tenderAward.setCreatedBy(usr.getId()); + tenderAward.setCreatedDate(new Date()); + tenderAward.setLastUpdatedBy(usr.getId()); + tenderAward.setLastUpdatedDate(new Date()); + + try { + tenderService.awardTender(tenderAward); + } catch (Exception ex) { + AlertDTO alert = new AlertDTO(AlertDTO.AlertType.DANGER, + ex.getMessage()); + redirectAttrs.addFlashAttribute("alert", alert); + return "redirect:/admin/tender/award/" + id; + } + + AlertDTO alert = new AlertDTO(AlertDTO.AlertType.SUCCESS, "Tender Awarded"); + redirectAttrs.addFlashAttribute("alert", alert); + return "redirect:/admin/tender/award"; + } +} diff --git a/src/main/java/com/chlorocode/tendertracker/web/admin/TenderClarificationController.java b/src/main/java/com/chlorocode/tendertracker/web/admin/TenderClarificationController.java index 6ea3e2d..890fb0a 100644 --- a/src/main/java/com/chlorocode/tendertracker/web/admin/TenderClarificationController.java +++ b/src/main/java/com/chlorocode/tendertracker/web/admin/TenderClarificationController.java @@ -1,7 +1,6 @@ package com.chlorocode.tendertracker.web.admin; import com.chlorocode.tendertracker.dao.dto.AlertDTO; -import com.chlorocode.tendertracker.dao.dto.EvaluateCriteriaDTO; import com.chlorocode.tendertracker.dao.dto.TenderClarificationDTO; import com.chlorocode.tendertracker.dao.entity.*; import com.chlorocode.tendertracker.logging.TTLogger; @@ -21,7 +20,7 @@ import java.util.List; /** - * Created by andy on 8/8/2017. + * Controller for tender clarification page. */ @Controller public class TenderClarificationController { @@ -30,6 +29,13 @@ public class TenderClarificationController { private String className; private CodeValueService codeValueService; + /** + * Constructor. + * + * @param clariSvc ClarificationService + * @param userSvc UserService + * @param codeValueService CodeValueService + */ @Autowired public TenderClarificationController(ClarificationService clariSvc,UserService userSvc,CodeValueService codeValueService){ this.clariSvc = clariSvc; @@ -38,21 +44,43 @@ public TenderClarificationController(ClarificationService clariSvc,UserService u this.codeValueService = codeValueService; } + /** + * This method is used to display page containing list of tender clarifications. + * + * @return String + */ @GetMapping("/admin/tender/clarification") public String showTenderClarificationPage() { return "admin/clarification/tenderClarificationList"; } + /** + * This method is used to display tender clarification details. + * + * @param id unique identifier of the tender clarification + * @param model ModelMap + * @return String + */ @GetMapping("/admin/tender/clarification/view/{id}") public String showTenderClarificationUpdatePage(@PathVariable(value = "id") Integer id,ModelMap model) { Clarification clarfi = clariSvc.findById(id); - if(clarfi == null){ + if (clarfi == null) { AlertDTO alert = new AlertDTO(AlertDTO.AlertType.DANGER, "unable to find the clarification based on this id " + id); model.addAttribute("alert", alert); return "admin/clarification/tenderClarificationList"; } - try{ + + //perform validation check, if the tender is not created by this company, stop to view it + CurrentUser usr1 = (CurrentUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); + if (clarfi.getTender().getCompany().getId() != usr1.getSelectedCompany().getId()) + { + AlertDTO alert = new AlertDTO(AlertDTO.AlertType.DANGER, + "You are not auhtorized to view the tender clarification details"); + model.addAttribute("alert", alert); + return "admin/clarification/tenderClarificationList"; + } + try { User usr = userSvc.findById(clarfi.getCreatedBy()); TenderClarificationDTO dto = new TenderClarificationDTO(); dto.setId(clarfi.getId()); @@ -69,17 +97,15 @@ public String showTenderClarificationUpdatePage(@PathVariable(value = "id") Inte dto.setSubmittedDate(clarfi.getCreatedDate()); dto.setResponse(clarfi.getResponse()); List lstCode = codeValueService.getByType("tender_type"); - for(int i = 0; i < lstCode.size(); i++){ - CodeValue code = lstCode.get(i); - if(code.getCode() == clarfi.getTender().getTenderType()){ + for (CodeValue code : lstCode) { + if (code.getCode() == clarfi.getTender().getTenderType()) { dto.setTenderType(code.getDescription()); break; } } - //dto.setTenderType(clarfi.getTender().getTenderType()); model.addAttribute("clarificationDto",dto); - }catch(Exception ex){ + } catch (Exception ex) { TTLogger.error(className,"error: ", ex ); AlertDTO alert = new AlertDTO(AlertDTO.AlertType.DANGER, "Failed to retrieve tender clarification.Please contact administrator"); @@ -87,13 +113,21 @@ public String showTenderClarificationUpdatePage(@PathVariable(value = "id") Inte return "admin/clarification/tenderClarificationList"; } - return "admin/clarification/tenderClarificationView"; } + /** + * This method is used to submit tender clarification. + * + * @param model ModelMap + * @param form input data from user + * @param tenderId unique identifier of the tender + * @return String + * @see TenderClarificationDTO + */ @PostMapping("/tender/clarification/save") - public String saveTenderClarification(ModelMap model,@Valid TenderClarificationDTO form, - @RequestParam("tenderId") int tenderId,@RequestParam("companyId") int companyId){ + public String saveTenderClarification(ModelMap model, @Valid TenderClarificationDTO form, + @RequestParam("tenderId") int tenderId){ CurrentUser usr = (CurrentUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); Company company = usr.getSelectedCompany(); @@ -109,9 +143,15 @@ public String saveTenderClarification(ModelMap model,@Valid TenderClarificationD model.addAttribute("alert", alert); } return "redirect:/tender/" + tenderId; - // return "tenderDetails"; } + /** + * This method is used to response into tender clarification. + * + * @param form data inputted by user + * @param model ModelMap + * @return String + */ @PostMapping("/admin/tender/clarification/update") public String updateTenderClarificationResponse(@Valid TenderClarificationDTO form, ModelMap model){ diff --git a/src/main/java/com/chlorocode/tendertracker/web/admin/TenderController.java b/src/main/java/com/chlorocode/tendertracker/web/admin/TenderController.java index 91e8fd4..e37bed8 100644 --- a/src/main/java/com/chlorocode/tendertracker/web/admin/TenderController.java +++ b/src/main/java/com/chlorocode/tendertracker/web/admin/TenderController.java @@ -1,15 +1,9 @@ package com.chlorocode.tendertracker.web.admin; import com.chlorocode.tendertracker.dao.dto.*; -import com.chlorocode.tendertracker.dao.entity.CurrentUser; -import com.chlorocode.tendertracker.dao.entity.Tender; -import com.chlorocode.tendertracker.dao.entity.TenderItem; -import com.chlorocode.tendertracker.dao.entity.User; +import com.chlorocode.tendertracker.dao.entity.*; import com.chlorocode.tendertracker.exception.ApplicationException; -import com.chlorocode.tendertracker.service.CodeValueService; -import com.chlorocode.tendertracker.service.S3Wrapper; -import com.chlorocode.tendertracker.service.TenderService; -import com.chlorocode.tendertracker.service.UserService; +import com.chlorocode.tendertracker.service.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; @@ -30,6 +24,9 @@ import java.text.SimpleDateFormat; import java.util.Date; +/** + * Controller for the tender page in admin portal. + */ @Controller public class TenderController { @@ -37,27 +34,70 @@ public class TenderController { private TenderService tenderService; private S3Wrapper s3Service; private UserService userService; - + private CompanyService companyService; + private TenderItemService tenderItemService; + + /** + * Constructor. + * + * @param codeValueService CodeValueService + * @param tenderService TenderService + * @param s3Service S3Wrapper + * @param userService UserService + * @param companyService CompanyService + * @param tenderItemService TenderItemService + */ @Autowired - public TenderController(CodeValueService codeValueService, TenderService tenderService, S3Wrapper s3Service,UserService userService) { + public TenderController(CodeValueService codeValueService, TenderService tenderService, S3Wrapper s3Service, + UserService userService, CompanyService companyService, TenderItemService tenderItemService) { this.codeValueService = codeValueService; this.tenderService = tenderService; this.s3Service = s3Service; this.userService = userService; + this.companyService = companyService; + this.tenderItemService = tenderItemService; } + /** + * This method is used to display page to list all tenders of the company. + * + * @return String + */ @GetMapping("/admin/tender") public String showTenderPage() { return "admin/tender/tenderView"; } + /** + * This method is used to display page containing list of tenders to be evaluated. + * + * @return String + */ @GetMapping("/admin/tender/evaluation") public String showTenderEvaluationPage() { return "admin/tender/tenderEvaluationView"; } + /** + * This method is used to display create tender page. + * + * @param model ModelMap + * @param redirectAttrs RedirectAttributes + * @return String + */ @GetMapping("/admin/tender/create") - public String showCreateTenderPage(ModelMap model) { + public String showCreateTenderPage(ModelMap model, RedirectAttributes redirectAttrs) { + Authentication auth = SecurityContextHolder.getContext().getAuthentication(); + CurrentUser usr = (CurrentUser) auth.getPrincipal(); + Company comp = usr.getSelectedCompany(); + Company selectedComp = companyService.findById(comp.getId()); + if(!selectedComp.isActive()){ + AlertDTO alert = new AlertDTO(AlertDTO.AlertType.DANGER, + "This company had been blacklisted by Administrator. Kindly please contact Administrator for more details"); + redirectAttrs.addFlashAttribute("alert", alert); + return "redirect:/admin/tender"; + } + model.addAttribute("tender", new TenderCreateDTO()); model.addAttribute("tenderType", codeValueService.getByType("tender_type")); model.addAttribute("tenderCategories", codeValueService.getAllTenderCategories()); @@ -65,6 +105,22 @@ public String showCreateTenderPage(ModelMap model) { return "admin/tender/tenderCreate"; } + /** + * This method is used to create a tender. + * This method can handle request both from normal HTTP and AJAX. + * This method will return the name of next screen or null for AJAX response. + * For AJAX response, this method will return the HTTP status and any error in the HTTP body. + * + * @param form input data from user + * @param result binding result to check DTO validation result + * @param redirectAttrs RedirectAttributes + * @param model ModelMap + * @param request HttpServletRequest + * @param resp HttpServletResponse + * @return String + * @throws IOException if has exception when putting error message in AJAX response + * @see TenderCreateDTO + */ @PostMapping("/admin/tender/create") public String saveCreateTender(@Valid @ModelAttribute("tender") TenderCreateDTO form, BindingResult result, RedirectAttributes redirectAttrs, ModelMap model, HttpServletRequest request, @@ -130,6 +186,18 @@ public String saveCreateTender(@Valid @ModelAttribute("tender") TenderCreateDTO } try { + if (t.getTenderType() == 2) { + if (form.getInvitedCompany() == null || form.getInvitedCompany().trim().equals("")) { + throw new ApplicationException("For Closed Tender, please provide at least one company to be invited"); + } + + String[] companyId = form.getInvitedCompany().split(","); + for (String c : companyId) { + Company company = companyService.findById(Integer.parseInt(c)); + t.addInvitedCompany(company); + } + } + tenderService.createTender(t, form.getAttachments()); AlertDTO alert = new AlertDTO(AlertDTO.AlertType.SUCCESS, @@ -168,7 +236,11 @@ public void setAsText(String value) { try { setValue(new SimpleDateFormat("dd/MM/yyyy HH:mm").parse(value)); } catch(ParseException e) { - setValue(null); + try { + setValue(new SimpleDateFormat("dd/MM/yyyy").parse(value)); + } catch(ParseException e2) { + setValue(null); + } } } @@ -182,8 +254,16 @@ public String getAsText() { }); } + /** + * This method is used to display page containing tender details. + * + * @param id unique identifier of the tender + * @param model ModelMap + * @param redirectAttrs RedirectAttributes + * @return String + */ @GetMapping("/admin/tender/{id}") - public String showTenderDetails(@PathVariable(value="id") Integer id, ModelMap model,RedirectAttributes redirectAttrs) { + public String showTenderDetails(@PathVariable(value="id") Integer id, ModelMap model, RedirectAttributes redirectAttrs) { Tender tender = tenderService.findById(id); if (tender == null) { return "redirect:/admin/tender"; @@ -208,6 +288,13 @@ public String showTenderDetails(@PathVariable(value="id") Integer id, ModelMap m return "admin/tender/tenderDetails"; } + /** + * This method is used to display update tender page. + * + * @param id unique identifier of the tender + * @param model ModelMap + * @return String + */ @GetMapping("/admin/tender/{id}/update") public String showTenderUpdatePage(@PathVariable(value="id") Integer id, ModelMap model) { Tender tender = tenderService.findById(id); @@ -248,9 +335,20 @@ public String showTenderUpdatePage(@PathVariable(value="id") Integer id, ModelMa model.addAttribute("tenderCategories", codeValueService.getAllTenderCategories()); model.addAttribute("uom", codeValueService.getByType("uom")); model.addAttribute("s3Service", s3Service); + model.addAttribute("maxTenderItemIndex", tender.getItems().size() - 1); return "admin/tender/tenderUpdate"; } + /** + * This method is used to update tender information. + * + * @param form input data from user + * @param redirectAttrs RedirectAttributes + * @param result binding result to check DTO validation + * @param model ModelMap + * @return String + * @see TenderUpdateDTO + */ @PostMapping("/admin/tender/update") public String updateTender(@Valid @ModelAttribute("tender") TenderUpdateDTO form, RedirectAttributes redirectAttrs, BindingResult result, ModelMap model) { @@ -290,6 +388,11 @@ public String updateTender(@Valid @ModelAttribute("tender") TenderUpdateDTO form tender.setLastUpdatedBy(usr.getId()); tender.setLastUpdatedDate(new Date()); + Date current = new Date(); + if(current.after(tender.getClosedDate())){ + tender.setStatus(2); + } + try { tenderService.updateTender(tender); } catch (ApplicationException ex) { @@ -304,9 +407,19 @@ public String updateTender(@Valid @ModelAttribute("tender") TenderUpdateDTO form return "redirect:/admin/tender/" + form.getTenderId() + "/update"; } + /** + * This method is used to add new tender item. + * + * @param form input data from user + * @param tenderId unique identifier of the tender + * @param result binding result to check DTO validation + * @param redirectAttrs RedirectAttributes + * @return String + * @see TenderItemUpdateDTO + */ @PostMapping("/admin/tender/addTenderItem") public String addTenderItem(@Valid TenderItemUpdateDTO form, @RequestParam(name = "tenderId") int tenderId, - BindingResult result, ModelMap model, RedirectAttributes redirectAttrs) { + BindingResult result, RedirectAttributes redirectAttrs) { if (result.hasErrors()) { AlertDTO alert = new AlertDTO(result.getAllErrors()); redirectAttrs.addFlashAttribute("alert", alert); @@ -326,16 +439,34 @@ public String addTenderItem(@Valid TenderItemUpdateDTO form, @RequestParam(name tenderItem.setLastUpdatedDate(new Date()); tenderItem.setTender(tender); - tenderService.addTenderItem(tenderItem); + try { + tenderItemService.addTenderItem(tenderItem); + } catch (ApplicationException ex) { + AlertDTO alert = new AlertDTO(AlertDTO.AlertType.DANGER, + ex.getMessage()); + redirectAttrs.addFlashAttribute("alert", alert); + return "redirect:/admin/tender/" + tender.getId() + "/update"; + } AlertDTO alert = new AlertDTO(AlertDTO.AlertType.SUCCESS, "Tender Item Added"); redirectAttrs.addFlashAttribute("alert", alert); return "redirect:/admin/tender/" + tenderId + "/update"; } + /** + * This method is used to update tender item. + * + * @param tenderId unique identifier of the tender + * @param tenderItemId unique identifier of the tender item + * @param form input data from user + * @param result binding result to check DTO validation + * @param redirectAttrs RedirectAttributes + * @return String + * @see TenderItemUpdateDTO + */ @PostMapping("/admin/tender/updateTenderItem") public String updateTenderItem(@RequestParam(name = "tenderId") int tenderId, @RequestParam("tenderItemId") int tenderItemId, - @Valid TenderItemUpdateDTO form, BindingResult result, ModelMap model, RedirectAttributes redirectAttrs) { + @Valid TenderItemUpdateDTO form, BindingResult result, RedirectAttributes redirectAttrs) { if (result.hasErrors()) { AlertDTO alert = new AlertDTO(result.getAllErrors()); redirectAttrs.addFlashAttribute("alert", alert); @@ -344,30 +475,93 @@ public String updateTenderItem(@RequestParam(name = "tenderId") int tenderId, @R CurrentUser usr = (CurrentUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); - TenderItem tenderItem = tenderService.findTenderItemById(tenderItemId); + TenderItem tenderItem = tenderItemService.findTenderItemById(tenderItemId); tenderItem.setUom(form.getUom()); tenderItem.setQuantity(form.getQuantity()); tenderItem.setDescription(form.getDescription()); tenderItem.setLastUpdatedBy(usr.getId()); tenderItem.setLastUpdatedDate(new Date()); - tenderService.updateTenderItem(tenderItem); + try { + tenderItemService.updateTenderItem(tenderItem); + } catch (ApplicationException ex) { + AlertDTO alert = new AlertDTO(AlertDTO.AlertType.DANGER, + ex.getMessage()); + redirectAttrs.addFlashAttribute("alert", alert); + return "redirect:/admin/tender/" + tenderItem.getTender().getId() + "/update"; + } AlertDTO alert = new AlertDTO(AlertDTO.AlertType.SUCCESS, "Tender Item Updated"); redirectAttrs.addFlashAttribute("alert", alert); return "redirect:/admin/tender/" + tenderId + "/update"; } + /** + * This method is used to remove tender item. + * + * @param tenderItemId unique identifier of the tender item + * @param tenderId unique identifier of the tender + * @param redirectAttrs RedirectAttributes + * @return String + */ @PostMapping("/admin/tender/removeTenderItem") public String removeTenderItem(@RequestParam(name = "tenderItemId") int tenderItemId, @RequestParam(name = "tenderId") int tenderId, RedirectAttributes redirectAttrs) { - tenderService.removeTenderItem(tenderItemId); + tenderItemService.removeTenderItem(tenderItemId); AlertDTO alert = new AlertDTO(AlertDTO.AlertType.SUCCESS, "Tender Item Removed"); redirectAttrs.addFlashAttribute("alert", alert); return "redirect:/admin/tender/" + tenderId + "/update"; } + /** + * This method is used to move the tender item sequence up. + * + * @param tenderItemId unique identifier of the tender item + * @param tenderId unique identifier of the tender + * @param redirectAttrs RedirectAttributes + * @return String + */ + @PostMapping("/admin/tender/moveUpTenderItem") + public String moveUpTenderItem(@RequestParam(name = "tenderItemId") int tenderItemId, @RequestParam(name = "tenderId") int tenderId, + RedirectAttributes redirectAttrs) { + tenderItemService.moveUpTenderItem(tenderItemId, tenderId); + + AlertDTO alert = new AlertDTO(AlertDTO.AlertType.SUCCESS, "Tender Item Order Updated"); + redirectAttrs.addFlashAttribute("alert", alert); + return "redirect:/admin/tender/" + tenderId + "/update"; + } + + /** + * This method is used to move the tender item sequence down. + * + * @param tenderItemId unique identifier of the tender item + * @param tenderId unique identifier of the tender + * @param redirectAttrs RedirectAttributes + * @return String + */ + @PostMapping("/admin/tender/moveDownTenderItem") + public String moveDownTenderItem(@RequestParam(name = "tenderItemId") int tenderItemId, @RequestParam(name = "tenderId") int tenderId, + RedirectAttributes redirectAttrs) { + tenderItemService.moveDownTenderItem(tenderItemId, tenderId); + + AlertDTO alert = new AlertDTO(AlertDTO.AlertType.SUCCESS, "Tender Item Order Updated"); + redirectAttrs.addFlashAttribute("alert", alert); + return "redirect:/admin/tender/" + tenderId + "/update"; + } + + /** + * This method is used to add tender document. + * This method can handle request both from normal HTTP and AJAX. + * This method will return the name of next screen or null for AJAX response. + * For AJAX response, this method will return the HTTP status and any error in the HTTP body. + * + * @param files new tender document to be added + * @param tenderId unique identifier of the tender + * @param resp HttpServletResponse + * @return String + * @throws IOException if has exception when putting error message in AJAX response + */ @PostMapping("/admin/tender/addTenderDocument") public String addTenderDocument(@RequestParam(name = "file") MultipartFile files, @RequestParam(name = "tenderId") int tenderId, HttpServletResponse resp) throws IOException { @@ -389,6 +583,14 @@ public String addTenderDocument(@RequestParam(name = "file") MultipartFile files } } + /** + * This method is used to remove tender document from a tender. + * + * @param documentId unique identifier of the document + * @param tenderId unique identifier of the tender + * @param redirectAttrs RedirectAttributes + * @return String + */ @PostMapping("/admin/tender/removeTenderDocument") public String removeTenderDocument(@RequestParam(name = "id") int documentId, @RequestParam(name = "tenderId") int tenderId, RedirectAttributes redirectAttrs) { diff --git a/src/main/java/com/chlorocode/tendertracker/web/admin/TenderEvaluationController.java b/src/main/java/com/chlorocode/tendertracker/web/admin/TenderEvaluationController.java new file mode 100644 index 0000000..2d9797a --- /dev/null +++ b/src/main/java/com/chlorocode/tendertracker/web/admin/TenderEvaluationController.java @@ -0,0 +1,146 @@ +package com.chlorocode.tendertracker.web.admin; + +import com.chlorocode.tendertracker.dao.dto.AlertDTO; +import com.chlorocode.tendertracker.dao.entity.*; +import com.chlorocode.tendertracker.service.*; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.context.request.WebRequest; +import org.springframework.web.servlet.mvc.support.RedirectAttributes; + +import java.util.Date; +import java.util.LinkedList; +import java.util.List; + +/** + * Controller for tender evaluation page. + */ +@Controller +public class TenderEvaluationController { + + private EvaluationService evaluationService; + private BidService bidService; + private TenderService tenderService; + private CodeValueService codeValueService; + private S3Wrapper s3Wrapper; + + /** + * Constructor. + * + * @param evaluationService EvaluationService + * @param bidService BidService + * @param tenderService TenderService + * @param codeValueService CodeValueService + * @param s3Wrapper S3Wrapper + */ + @Autowired + public TenderEvaluationController(EvaluationService evaluationService, BidService bidService, + TenderService tenderService, CodeValueService codeValueService, S3Wrapper s3Wrapper) { + this.evaluationService = evaluationService; + this.bidService = bidService; + this.tenderService = tenderService; + this.codeValueService = codeValueService; + this.s3Wrapper = s3Wrapper; + } + + /** + * This method is used to display page containing list of bids to be evaluated. + * + * @param id unique identifier of the tender + * @param model ModelMap + * @return String + */ + @GetMapping("admin/tender/evaluation/{id}/bid") + public String showTenderEvaluationBidListPage(@PathVariable(value="id") Integer id, ModelMap model) { + Tender tender = tenderService.findById(id); + CurrentUser usr = (CurrentUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); + + model.addAttribute("tender", tender); + model.addAttribute("evaluationService", evaluationService); + model.addAttribute("userid", usr.getId()); + return "admin/tender/tenderEvaluationBidList"; + } + + /** + * This method is used to display submit evaluation page. + * + * @param id unique identifier of the bid + * @param model ModelMap + * @return String + */ + @GetMapping("admin/tender/submitEvaluation/{id}") + public String showSubmitTenderEvaluationPage(@PathVariable(value="id") Integer id, ModelMap model) { + Bid bid = bidService.findById(id); + List notifications = new LinkedList<>(); + List criteria = evaluationService.findEvaluationCriteriaByTender(bid.getTender().getId()); + + double totalBidAmount = 0; + for (BidItem bi : bid.getBidItems()) { + totalBidAmount += bi.getAmount(); + } + + if (totalBidAmount > bid.getTender().getEstimatePurchaseValue()) { + notifications.add("Exceed EPV"); + } + if (!bid.getCompany().isActive()) { + notifications.add("Company is Blacklisted"); + } + + model.addAttribute("tender", bid.getTender()); + model.addAttribute("bid", bid); + model.addAttribute("codeValueService", codeValueService); + model.addAttribute("totalBidAmount", totalBidAmount); + model.addAttribute("notifications", notifications); + model.addAttribute("criteria", criteria); + model.addAttribute("s3Service", s3Wrapper); + return "admin/tender/tenderEvaluationSubmit"; + } + + /** + * This method is used to submit tender evaluation. + * + * @param id unique identifier of the bid + * @param request WebRequest + * @param redirectAttrs RedirectAttributes + * @return String + */ + @PostMapping("admin/tender/submitEvaluation/{id}") + public String submitTenderEvaluation(@PathVariable(value="id") Integer id, WebRequest request, RedirectAttributes redirectAttrs) { + Bid bid = bidService.findById(id); + List criteria = evaluationService.findEvaluationCriteriaByTender(bid.getTender().getId()); + CurrentUser usr = (CurrentUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); + + List results = new LinkedList<>(); + for (EvaluationCriteria c : criteria) { + EvaluationResult res = new EvaluationResult(); + res.setBid(bid); + res.setResult(Integer.parseInt(request.getParameter("criteria_" + Integer.toString(c.getId())))); + res.setCriteria(c); + res.setEvaluator(usr.getUser()); + res.setCreatedBy(usr.getId()); + res.setCreatedDate(new Date()); + res.setLastUpdatedBy(usr.getId()); + res.setLastUpdatedDate(new Date()); + + results.add(res); + } + + try { + evaluationService.saveEvaluationResult(results); + } catch (Exception ex) { + AlertDTO alert = new AlertDTO(AlertDTO.AlertType.DANGER, + ex.getMessage()); + redirectAttrs.addFlashAttribute("alert", alert); + return "redirect:/admin/tender/evaluation/" + bid.getTender().getId() + "/bid"; + } + + AlertDTO alert = new AlertDTO(AlertDTO.AlertType.SUCCESS, "Evaluation Submitted"); + redirectAttrs.addFlashAttribute("alert", alert); + return "redirect:/admin/tender/evaluation/" + bid.getTender().getId() + "/bid"; + } +} diff --git a/src/main/java/com/chlorocode/tendertracker/web/admin/TenderReportsController.java b/src/main/java/com/chlorocode/tendertracker/web/admin/TenderReportsController.java new file mode 100644 index 0000000..9228691 --- /dev/null +++ b/src/main/java/com/chlorocode/tendertracker/web/admin/TenderReportsController.java @@ -0,0 +1,277 @@ +package com.chlorocode.tendertracker.web.admin; + +import com.chlorocode.tendertracker.dao.dto.AlertDTO; +import com.chlorocode.tendertracker.dao.dto.ProcurementReportDTO; +import com.chlorocode.tendertracker.service.CodeValueService; +import com.chlorocode.tendertracker.service.ReportService; +import com.chlorocode.tendertracker.service.TenderService; +import com.itextpdf.kernel.color.Color; +import com.itextpdf.kernel.pdf.PdfDocument; +import com.itextpdf.kernel.pdf.PdfWriter; +import com.itextpdf.layout.Document; +import com.itextpdf.layout.element.Cell; +import com.itextpdf.layout.element.Paragraph; +import com.itextpdf.layout.element.Table; +import com.itextpdf.layout.property.TextAlignment; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.OutputStream; +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.List; + +/** + * Controller for report page in admin portal. + */ +@Controller +public class TenderReportsController { + + public static final String PROCUREMENTREPORT_HEADER = "Ref. No,Tender Name,Category,Tender Type,Start Date,End Date,Status\n"; + public static final DateFormat DATEFORMAT = new SimpleDateFormat("dd/MM/yyyy"); + public static final String CSV_DELIMITER = ","; + public static final String NO_RESULTS = "No results are found for the selected criteria"; + + private ReportService reportService; + private CodeValueService codeValueService; + private TenderService tenderService; + + /** + * Constructor. + * + * @param reportService ReportService + * @param codeValueService CodeValueService + * @param tenderService TenderService + */ + @Autowired + public TenderReportsController(ReportService reportService, CodeValueService codeValueService, TenderService tenderService) { + this.reportService = reportService; + this.codeValueService = codeValueService; + this.tenderService = tenderService; + } + + /** + * This method is used to display procurement report page. + * + * @param model ModelMap + * @return String + */ + @GetMapping("/admin/report/procurementreport") + public String viewReportsPage(ModelMap model){ + model.addAttribute("tenderType", codeValueService.getByType("tender_type")); + model.addAttribute("tenderCategories", codeValueService.getAllTenderCategories()); + return "admin/reports/procurementReport"; + } + + /** + * This method is used to download procurement report/ + * + * @param model ModelMap + * @param request HttpServletRequest + * @param response HttpServletResponse + */ + @PostMapping("/admin/report/procurementreport") + public void downloadProcurementReport(ModelMap model, + HttpServletRequest request, HttpServletResponse response) { + + String openingDateFrom = request.getParameter("openingDateFrom"); + String openingDateTo = request.getParameter("openingDateTo"); + String closingDateFrom = request.getParameter("closingDateFrom"); + String closingDateTo = request.getParameter("closingDateTo"); + String category = request.getParameter("category"); + String status = request.getParameter("status"); + String fileType = request.getParameter("fileType"); + try { + List procurementReportList = null; + procurementReportList = reportService.findAllByDateRange( + DATEFORMAT.parse(openingDateFrom), DATEFORMAT.parse(openingDateTo), + DATEFORMAT.parse(closingDateFrom), DATEFORMAT.parse(closingDateTo), + category, status); + if(fileType.equals("pdf")) { + downloadProcurementReportPdf(response, procurementReportList); + } + if(fileType.equals("csv")){ + downloadProcurementReportCSV(response, procurementReportList); + } + + } catch (ParseException ex) { + AlertDTO alert = new AlertDTO(AlertDTO.AlertType.DANGER, + ex.getMessage()); + model.addAttribute("alert", alert); + } catch (IOException e) { + AlertDTO alert = new AlertDTO(AlertDTO.AlertType.DANGER, + e.getMessage()); + } + + } + + /** + * This method is used to generate procurement report in CSV format. + * + * @param response HttpServletResponse + * @param procurementReportList report data + * @throws IOException if unable to send out the response + */ + private void downloadProcurementReportCSV(HttpServletResponse response, List procurementReportList) throws IOException { + response.setContentType("application/ms-excel"); // or you can use text/csv + response.setHeader("Content-Disposition", "attachment; filename=procurementreport.csv"); + OutputStream out = response.getOutputStream(); + out.write(PROCUREMENTREPORT_HEADER.getBytes()); + if(procurementReportList.isEmpty()) { + out.write(NO_RESULTS.getBytes()); + } + + for (ProcurementReportDTO procurementReportDTO : procurementReportList) { + String line=new String(procurementReportDTO.getRefNum() + + CSV_DELIMITER +procurementReportDTO.getTenderName() + + CSV_DELIMITER +procurementReportDTO.getTenderCategory() + + CSV_DELIMITER +procurementReportDTO.getTenderType() + + CSV_DELIMITER +DATEFORMAT.format(procurementReportDTO.getOpeningDate()) + + CSV_DELIMITER +DATEFORMAT.format(procurementReportDTO.getClosingDate()) + + CSV_DELIMITER +procurementReportDTO.getTenderStatus() + +"\n"); + + out.write(line.toString().getBytes()); + } + out.flush(); + out.close(); + } + + /** + * This method is used to generate procurement report in PDF format. + * + * @param response HttpServletResponse + * @param procurementReportList report data + * @throws IOException if unable to send out the response + */ + private void downloadProcurementReportPdf(HttpServletResponse response, + List procurementReportList) throws IOException { + + OutputStream out = response.getOutputStream(); + // Apply preferences and build metadata + response.setContentType("application/pdf"); + response.setHeader("Content-Disposition", "attachment; filename=procurementreport.pdf"); + PdfWriter writer = new PdfWriter(out); + PdfDocument pdfDocument = new PdfDocument(writer); + + Document document = new Document(pdfDocument); + + document.add(new Paragraph("Tender Procurement Report")); + + Table table = new Table(8); + table.addHeaderCell("Sl. No"); + table.addHeaderCell("Ref. No"); + table.addHeaderCell("Tender Name"); + table.addHeaderCell("Category"); + table.addHeaderCell("Tender Type"); + table.addHeaderCell("Start Date"); + table.addHeaderCell("End Date"); + table.addHeaderCell("Status"); + table.getHeader().setBackgroundColor(Color.LIGHT_GRAY); + table.getHeader().setBold(); + table.setFontSize(8.0f); + System.out.println(); + if(procurementReportList.isEmpty()) { + Cell cell = new Cell(1, 8) + .setTextAlignment(TextAlignment.CENTER) + .add(NO_RESULTS); + table.addCell(cell); + } + int slNo = 1; + for (ProcurementReportDTO procurementReportDTO : procurementReportList) { + table.addCell(String.valueOf(slNo++)); + table.addCell(procurementReportDTO.getRefNum()); + table.addCell(procurementReportDTO.getTenderName()); + table.addCell(procurementReportDTO.getTenderCategory()); + table.addCell(procurementReportDTO.getTenderType()); + table.addCell(DATEFORMAT.format(procurementReportDTO.getOpeningDate())); + table.addCell(DATEFORMAT.format(procurementReportDTO.getClosingDate())); + table.addCell(procurementReportDTO.getTenderStatus()); + } + document.add(table); + document.close(); + + response.setHeader("Content-Disposition", "attachment"); // make browser to ask for download/display + out.flush(); + out.close(); + } + + /** + * This method is used to display statistic report page. + * + * @param model ModelMap + * @return String + */ + @GetMapping("/admin/report/statisticsreport") + public String viewStatisticsReportsPage(ModelMap model){ + model.addAttribute("tenderType", codeValueService.getByType("tender_type")); + model.addAttribute("tenderCategories", codeValueService.getAllTenderCategories()); + return "admin/reports/statisticsReport"; + } + + /** + * This method is used to generate statistic report. + * + * @param model ModelMap + * @param request HttpServletRequest + * @return String + */ + @PostMapping("/admin/report/statisticsreport") + public String downloadStatisticsReport(ModelMap model, + HttpServletRequest request) { + + String fromDate = request.getParameter("fromDate"); + String toDate = request.getParameter("toDate"); + + try { + model.addAttribute("fromDate",fromDate); + model.addAttribute("toDate",toDate); + model.addAttribute("tenderSummary", reportService.findTenderSummary( + DATEFORMAT.parse(fromDate),DATEFORMAT.parse(toDate))); + model.addAttribute("companySummary", reportService.findCompanySummary( + DATEFORMAT.parse(fromDate),DATEFORMAT.parse(toDate))); + + } catch (ParseException ex) { + AlertDTO alert = new AlertDTO(AlertDTO.AlertType.DANGER, + ex.getMessage()); + model.addAttribute("alert", alert); + } + + return "admin/reports/statisticsReport"; + } + + /** + * This method is used to display page containing the list of tenders to be selected to view the analytic report. + * + * @return String + */ + @GetMapping("/admin/report/analyticreport") + public String viewAnalyticReportList() { + return "admin/reports/analyticReport"; + } + + /** + * This method is used to display analytic details page. + * + * @param id unique identifier of the tender + * @param model ModelMap + * @return String + */ + @GetMapping("/admin/report/analyticreport/{id}") + public String viewAnalyticReportDetail(@PathVariable(value="id") int id, ModelMap model) { + model.addAttribute("tender", tenderService.findById(id)); + model.addAttribute("visit", reportService.getNumberOfVisit(id)); + model.addAttribute("uniqueVisit", reportService.getNumberOfUniqueVisit(id)); + model.addAttribute("topCountryVisit", reportService.getTopCountryVisitor(id)); + + return "admin/reports/analyticReportDetails"; + } +} diff --git a/src/main/java/com/chlorocode/tendertracker/web/data/BidDataController.java b/src/main/java/com/chlorocode/tendertracker/web/data/BidDataController.java new file mode 100644 index 0000000..7e0fa54 --- /dev/null +++ b/src/main/java/com/chlorocode/tendertracker/web/data/BidDataController.java @@ -0,0 +1,81 @@ +package com.chlorocode.tendertracker.web.data; + +import com.chlorocode.tendertracker.dao.BidDAO; +import com.chlorocode.tendertracker.dao.TenderDataAppealDAO; +import com.chlorocode.tendertracker.dao.entity.Bid; +import com.chlorocode.tendertracker.dao.entity.CurrentUser; +import com.chlorocode.tendertracker.dao.entity.TenderAppeal; +import com.fasterxml.jackson.annotation.JsonView; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.jpa.datatables.mapping.DataTablesInput; +import org.springframework.data.jpa.datatables.mapping.DataTablesOutput; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +import javax.validation.Valid; + +/** + * REST Controller for bid. + */ +@RestController +public class BidDataController { + + private BidDAO bidDAO; + private TenderDataAppealDAO dao; + + /** + * Constructor + * + * @param bidDAO BidDAO + * @param dao TenderDataAppealDAO + */ + @Autowired + public BidDataController(BidDAO bidDAO, TenderDataAppealDAO dao) { + this.bidDAO = bidDAO; + this.dao = dao; + } + + /** + * This method is used to return list of bids for DataTable. + * + * @param input DataTable search input + * @return DataTable output + */ + @JsonView(DataTablesOutput.View.class) + @RequestMapping(value = "/admin/data/bids", method = RequestMethod.GET) + public DataTablesOutput getTenders(@Valid DataTablesInput input) { + CurrentUser usr = (CurrentUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); + int companyId = usr.getSelectedCompany().getId(); + + DataTablesOutput bids = bidDAO.findAll(input, null, (root, criteriaQuery, criteriaBuilder) -> { + return criteriaBuilder.equal(root.join("company").get("id"), companyId); + }); + + return bids; + } + + + /** + * This method is used to return tender appeal list for DataTable. + * + * @param input DataTable search input + * @return DataTable output + */ + @JsonView(DataTablesOutput.View.class) + @RequestMapping(value = "/admin/data/tenderappeal", method = RequestMethod.GET) + public DataTablesOutput getTendersAppeal(@Valid DataTablesInput input) { + CurrentUser usr = (CurrentUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); + int companyId = usr.getSelectedCompany().getId(); + + DataTablesOutput bids = dao.findAll(input, null, (root, criteriaQuery, criteriaBuilder) -> { + return + criteriaBuilder.and( + criteriaBuilder.equal(root.join("tender").join("company").get("id"), companyId) + ); + }); + + return bids; + } +} diff --git a/src/main/java/com/chlorocode/tendertracker/web/data/CompanyDataController.java b/src/main/java/com/chlorocode/tendertracker/web/data/CompanyDataController.java index bc6764c..0eae408 100644 --- a/src/main/java/com/chlorocode/tendertracker/web/data/CompanyDataController.java +++ b/src/main/java/com/chlorocode/tendertracker/web/data/CompanyDataController.java @@ -1,27 +1,54 @@ package com.chlorocode.tendertracker.web.data; import com.chlorocode.tendertracker.dao.CompanyDAO; +import com.chlorocode.tendertracker.dao.TenderDAO; import com.chlorocode.tendertracker.dao.entity.Company; +import com.chlorocode.tendertracker.dao.entity.Tender; import com.fasterxml.jackson.annotation.JsonView; +import com.google.common.io.CharStreams; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.jpa.datatables.mapping.DataTablesInput; import org.springframework.data.jpa.datatables.mapping.DataTablesOutput; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import javax.servlet.http.HttpServletRequest; import javax.validation.Valid; +import java.io.IOException; +import java.util.List; +/** + * REST controller for company. + */ @RestController public class CompanyDataController { private CompanyDAO companyDAO; + private TenderDAO tenderDAO; + /** + * Constructor. + * + * @param companyDAO CompanyDAO + * @param tenderDAO TenderDAO + */ @Autowired - public CompanyDataController(CompanyDAO companyDAO) { + public CompanyDataController(CompanyDAO companyDAO, TenderDAO tenderDAO) { this.companyDAO = companyDAO; + this.tenderDAO = tenderDAO; } + /** + * This method is used to list company registrations to be reviewed. + * + * @param input DataTable search input + * @return DataTable output + */ @JsonView(DataTablesOutput.View.class) @RequestMapping(value = "/sysadm/data/companyregistrations", method = RequestMethod.GET) public DataTablesOutput getCompanyRegistrations(@Valid DataTablesInput input) { @@ -29,4 +56,144 @@ public DataTablesOutput getCompanyRegistrations(@Valid DataTablesInput return criteriaBuilder.equal(root.get("status"), 0); }); } + + /** + * This function is used to list all companies which already approved / rejected. + * + * @param input DataTable search input + * @return DataTable output + */ + @JsonView(DataTablesOutput.View.class) + @RequestMapping(value = "/sysadm/data/companyinfolist", method = RequestMethod.GET) + public DataTablesOutput getCompanyInfoList(@Valid DataTablesInput input) { + return companyDAO.findAll(input, null, (root, criteriaQuery, criteriaBuilder) -> { + return criteriaBuilder.notEqual(root.get("status"), 0); + }); + } + + /** + * This method is used to search company data by company name. + * + * @param name company name + * @return String + * @throws JSONException if error when forming JSON response + */ + @RequestMapping(path = "/admin/data/company", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) + public @ResponseBody String getCompanyName(@RequestParam(value="name", defaultValue="") String name) + throws JSONException { + JSONArray companies = new JSONArray(); + if (!name.trim().isEmpty()) { + List companyData = companyDAO.findCompanyByName(name); + for (Company c : companyData) { + JSONObject company = new JSONObject(); + company.put("id", c.getId()); + company.put("name", c.getName()); + companies.put(company); + } + } + return companies.toString(); + } + + /** + * This method is used to get the list of invited companies for a closed tender. + * + * @param id unique identifier of the tender + * @return String + * @throws JSONException if error when forming JSON response + */ + @RequestMapping(path = "/admin/data/invitedCompany/{tenderId}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity getTenderInvitedCompany(@PathVariable(value="tenderId") int id) + throws JSONException { + JSONArray companies = new JSONArray(); + Tender tender = tenderDAO.findOne(id); + + if (tender == null) { + return new ResponseEntity(HttpStatus.NOT_FOUND); + } + + for (Company c : tender.getInvitedCompanies()) { + JSONObject company = new JSONObject(); + company.put("id", Integer.toString(c.getId())); + company.put("name", c.getName()); + companies.put(company); + } + return new ResponseEntity<>(companies.toString(), HttpStatus.OK); + } + + /** + * This method is used to remove invited company for a closed tender. + * + * @param id unique identifier of the tender + * @param request HttpServletRequest + * @return String + * @throws JSONException if error when forming JSON response + * @throws IOException if error when writing JSON response + */ + @RequestMapping(path = "/admin/data/invitedCompany/{tenderId}", method = RequestMethod.DELETE, + produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity removeTenderInvitedCompany(@PathVariable(value="tenderId") int id, HttpServletRequest request) + throws JSONException, IOException { + Tender tender = tenderDAO.findOne(id); + JSONObject json = new JSONObject(CharStreams.toString(request.getReader())); + + if (tender == null) { + return new ResponseEntity(HttpStatus.NOT_FOUND); + } else if (tender.getTenderType() != 2) { + return new ResponseEntity(HttpStatus.BAD_REQUEST); + } + + for (Company c : tender.getInvitedCompanies()) { + if (c.getId() == json.getInt("companyId")) { + if (tender.getInvitedCompanies().size() == 1) { + return new ResponseEntity("Not allowed to removed all invited company for Closed Tender", HttpStatus.EXPECTATION_FAILED); + } + + tender.getInvitedCompanies().remove(c); + tenderDAO.save(tender); + + return new ResponseEntity(HttpStatus.OK); + } + } + + return new ResponseEntity(HttpStatus.NOT_FOUND); + } + + /** + * This method is used to add invited company for closed tender. + * + * @param id unique identifier of the tender + * @param request HttpServletRequest + * @return String + * @throws JSONException if error when forming JSON response + * @throws IOException if error when writing JSON response + */ + @RequestMapping(path = "/admin/data/invitedCompany/{tenderId}", method = RequestMethod.POST, + produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity addTenderInvitedCompany(@PathVariable(value="tenderId") int id, HttpServletRequest request) + throws JSONException, IOException { + Tender tender = tenderDAO.findOne(id); + JSONObject json = new JSONObject(CharStreams.toString(request.getReader())); + + if (tender == null) { + return new ResponseEntity(HttpStatus.NOT_FOUND); + } else if (tender.getTenderType() != 2) { + return new ResponseEntity(HttpStatus.BAD_REQUEST); + } + + Company company = companyDAO.findOne(json.getInt("companyId")); + if (company == null) { + return new ResponseEntity(HttpStatus.NOT_FOUND); + } + + for (Company c : tender.getInvitedCompanies()) { + if (c.getId() == company.getId()) { + // if company already exist, skip add process + return new ResponseEntity(HttpStatus.OK); + } + } + tender.addInvitedCompany(company); + tenderDAO.save(tender); + + return new ResponseEntity(HttpStatus.OK); + } } diff --git a/src/main/java/com/chlorocode/tendertracker/web/data/DashboardDataController.java b/src/main/java/com/chlorocode/tendertracker/web/data/DashboardDataController.java index 508d41f..6f51efb 100644 --- a/src/main/java/com/chlorocode/tendertracker/web/data/DashboardDataController.java +++ b/src/main/java/com/chlorocode/tendertracker/web/data/DashboardDataController.java @@ -14,16 +14,30 @@ import java.util.LinkedList; import java.util.List; +/** + * REST Controller for dashboard. + */ @RestController public class DashboardDataController { private TenderDAO tenderDAO; + /** + * Constructor. + * + * @param tenderDAO TenderDAO + */ @Autowired public DashboardDataController(TenderDAO tenderDAO) { this.tenderDAO = tenderDAO; } + /** + * This method is used to provide data for dashboard statistic. + * + * @return list of TenderStatusStatisticDTO + * @see TenderStatusStatisticDTO + */ @RequestMapping(value = "/admin/data/dashboard/tenderStatusStatistic", method = RequestMethod.GET, produces = "application/json") public @ResponseBody List getTenders() { CurrentUser usr = (CurrentUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); diff --git a/src/main/java/com/chlorocode/tendertracker/web/data/ProductDataClarificationController.java b/src/main/java/com/chlorocode/tendertracker/web/data/ProductDataClarificationController.java new file mode 100644 index 0000000..0dea93d --- /dev/null +++ b/src/main/java/com/chlorocode/tendertracker/web/data/ProductDataClarificationController.java @@ -0,0 +1,58 @@ +package com.chlorocode.tendertracker.web.data; + +import com.chlorocode.tendertracker.dao.ProductDataClarificationDAO; +import com.chlorocode.tendertracker.dao.entity.CurrentUser; +import com.chlorocode.tendertracker.dao.entity.ProductClarification; +import com.fasterxml.jackson.annotation.JsonView; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.jpa.datatables.mapping.DataTablesInput; +import org.springframework.data.jpa.datatables.mapping.DataTablesOutput; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +import javax.validation.Valid; + +/** + * REST controller for product clarification. + */ +@RestController +public class ProductDataClarificationController { + + private ProductDataClarificationDAO dao; + + /** + * Constructor. + * + * @param dao ProductClarificationDAO + */ + @Autowired + public ProductDataClarificationController(ProductDataClarificationDAO dao){ + this.dao = dao; + } + + /** + * This method is used to list all product clarifications/ + * + * @param input data table search criteria input + * @return data table output + */ + @JsonView(DataTablesOutput.View.class) + @RequestMapping(value = "/admin/data/productClarification", method = RequestMethod.GET) + public DataTablesOutput getProductClarification(@Valid DataTablesInput input) { + + CurrentUser usr = (CurrentUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); + int companyId = usr.getSelectedCompany().getId(); + + return dao.findAll(input, null, (root, criteriaQuery, cb) -> { + criteriaQuery.distinct(true); + return cb.and( + cb.equal(root.join("product").join("company").get("id"), companyId) + ); + }); + } + + + +} diff --git a/src/main/java/com/chlorocode/tendertracker/web/data/ProductDataController.java b/src/main/java/com/chlorocode/tendertracker/web/data/ProductDataController.java new file mode 100644 index 0000000..58cf0a4 --- /dev/null +++ b/src/main/java/com/chlorocode/tendertracker/web/data/ProductDataController.java @@ -0,0 +1,69 @@ +package com.chlorocode.tendertracker.web.data; + +import com.chlorocode.tendertracker.dao.ProductDAO; +import com.chlorocode.tendertracker.dao.entity.CurrentUser; +import com.chlorocode.tendertracker.dao.entity.Product; +import com.fasterxml.jackson.annotation.JsonView; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.jpa.datatables.mapping.DataTablesInput; +import org.springframework.data.jpa.datatables.mapping.DataTablesOutput; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +import javax.validation.Valid; + +/** + * REST controller for product. + */ +@RestController +public class ProductDataController { + + private ProductDAO productDAO; + + /** + * Constructor. + * + * @param productDAO ProductDAO + */ + @Autowired + public ProductDataController(ProductDAO productDAO) { + this.productDAO = productDAO; + } + + /** + * This method is used to search products for company admin portal. + * Only products belong to that company will be returned. + * + * @param input data table search criteria input + * @return data table output + */ + @JsonView(DataTablesOutput.View.class) + @RequestMapping(value = "/admin/data/products", method = RequestMethod.GET) + public DataTablesOutput getProducts(@Valid DataTablesInput input) { + CurrentUser user = (CurrentUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); + int companyId = user.getSelectedCompany().getId(); + + DataTablesOutput products = productDAO.findAll(input, null, (root, criteriaQuery, criteriaBuilder) -> { + return criteriaBuilder.equal(root.join("company").get("id"), companyId); + }); + + return products; + } + + /** + * This method is used to search all products for system admin portal. + * + * @param input data table search criteria input + * @return data table output + */ + @JsonView(DataTablesOutput.View.class) + @RequestMapping(value = "/sysadmin/data/product", method = RequestMethod.GET) + public DataTablesOutput getAllProductForSysAdmin(@Valid DataTablesInput input) { + + return productDAO.findAll(input, null, (root, criteriaQuery, criteriaBuilder) -> { + return criteriaBuilder.equal(root.get("status"), 0); + }); + } +} diff --git a/src/main/java/com/chlorocode/tendertracker/web/data/TenderDataClarificationController.java b/src/main/java/com/chlorocode/tendertracker/web/data/TenderDataClarificationController.java index 9e9a22d..b599b51 100644 --- a/src/main/java/com/chlorocode/tendertracker/web/data/TenderDataClarificationController.java +++ b/src/main/java/com/chlorocode/tendertracker/web/data/TenderDataClarificationController.java @@ -1,10 +1,8 @@ package com.chlorocode.tendertracker.web.data; -import com.chlorocode.tendertracker.dao.ClarificationDAO; import com.chlorocode.tendertracker.dao.TenderDataClarificationDAO; import com.chlorocode.tendertracker.dao.entity.Clarification; import com.chlorocode.tendertracker.dao.entity.CurrentUser; -import com.chlorocode.tendertracker.dao.entity.Tender; import com.fasterxml.jackson.annotation.JsonView; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.jpa.datatables.mapping.DataTablesInput; @@ -17,17 +15,29 @@ import javax.validation.Valid; /** - * Created by andy on 8/8/2017. + * REST controller for tender clarification. */ @RestController public class TenderDataClarificationController { + private TenderDataClarificationDAO clariDao; + /** + * Constructor. + * + * @param clariDao TenderDataClarificationDAO + */ @Autowired public TenderDataClarificationController(TenderDataClarificationDAO clariDao){ this.clariDao = clariDao; } + /** + * This method is used to search tender clarifications. + * + * @param input data table search criteria input + * @return data table output + */ @JsonView(DataTablesOutput.View.class) @RequestMapping(value = "/admin/data/tenderClarification", method = RequestMethod.GET) public DataTablesOutput getTenders(@Valid DataTablesInput input) { @@ -35,11 +45,6 @@ public DataTablesOutput getTenders(@Valid DataTablesInput input) CurrentUser usr = (CurrentUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); int companyId = usr.getSelectedCompany().getId(); -// return clariDao.findAll(input, null, (root, criteriaQuery, criteriaBuilder) -> { -// // return criteriaBuilder.equal(root.join("tender.company").get("id"), companyId); -// ); -// -// }); return clariDao.findAll(input, null, (root, criteriaQuery, cb) -> { criteriaQuery.distinct(true); return cb.and( diff --git a/src/main/java/com/chlorocode/tendertracker/web/data/TenderDataController.java b/src/main/java/com/chlorocode/tendertracker/web/data/TenderDataController.java index 31390a8..399f02c 100644 --- a/src/main/java/com/chlorocode/tendertracker/web/data/TenderDataController.java +++ b/src/main/java/com/chlorocode/tendertracker/web/data/TenderDataController.java @@ -1,37 +1,269 @@ package com.chlorocode.tendertracker.web.data; +import com.chlorocode.tendertracker.dao.EvaluationResultDAO; import com.chlorocode.tendertracker.dao.TenderDAO; -import com.chlorocode.tendertracker.dao.entity.CurrentUser; -import com.chlorocode.tendertracker.dao.entity.Tender; +import com.chlorocode.tendertracker.dao.entity.*; import com.fasterxml.jackson.annotation.JsonView; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.jpa.datatables.mapping.DataTablesInput; import org.springframework.data.jpa.datatables.mapping.DataTablesOutput; +import org.springframework.http.MediaType; import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; import javax.validation.Valid; +import java.util.HashSet; +/** + * REST controller for tender. + */ @RestController public class TenderDataController { private TenderDAO tenderDAO; + private EvaluationResultDAO evaResDAO; + /** + * Constrtuctor. + * + * @param tenderDAO TenderDAO + * @param evaResDAO EvaluationResultDAO + */ @Autowired - public TenderDataController(TenderDAO tenderDAO) { + public TenderDataController(TenderDAO tenderDAO, EvaluationResultDAO evaResDAO) { this.tenderDAO = tenderDAO; + this.evaResDAO = evaResDAO; } + /** + * This method is used to search tenders belong to a logged inc ompany. + * + * @param input data table search criteria input + * @return data table output + */ @JsonView(DataTablesOutput.View.class) @RequestMapping(value = "/admin/data/tenders", method = RequestMethod.GET) public DataTablesOutput getTenders(@Valid DataTablesInput input) { CurrentUser usr = (CurrentUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); int companyId = usr.getSelectedCompany().getId(); - return tenderDAO.findAll(input, null, (root, criteriaQuery, criteriaBuilder) -> { + DataTablesOutput tenders = tenderDAO.findAll(input, null, (root, criteriaQuery, criteriaBuilder) -> { return criteriaBuilder.equal(root.join("company").get("id"), companyId); }); + + return tenders; + } + + /** + * This method is used to search tenders created by all company. + * + * @param input data table search criteria input + * @return data table output + */ + @JsonView(DataTablesOutput.View.class) + @RequestMapping(value = "/sysadmin/data/tenderlist", method = RequestMethod.GET) + public DataTablesOutput getTendersList(@Valid DataTablesInput input) { + CurrentUser usr = (CurrentUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); + int companyId = usr.getSelectedCompany().getId(); + + DataTablesOutput tenders = tenderDAO.findAll(input, null, (root, criteriaQuery, criteriaBuilder) -> { + return criteriaBuilder.notEqual(root.get("status"), 5); + }); + + return tenders; + } + + /** + * This method is used to search tenders ready for evaluation. + * + * @param input data table search criteria input + * @return data table output + */ + @JsonView(DataTablesOutput.View.class) + @RequestMapping(value = "/admin/data/evaluatetenders", method = RequestMethod.GET) + public DataTablesOutput getEvaluateTenderList(@Valid DataTablesInput input) { + CurrentUser usr = (CurrentUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); + int companyId = usr.getSelectedCompany().getId(); + + DataTablesOutput tenders = tenderDAO.findAll(input, null, (root, criteriaQuery, criteriaBuilder) -> { + return criteriaBuilder.and( + criteriaBuilder.equal(root.join("company").get("id"), companyId), + criteriaBuilder.equal(root.get("status"), 2) + ); + }); + + return tenders; + } + + /** + * This method is used to search tenders to be awarded. + * + * @param input data table search criteria input + * @return data table output + */ + @JsonView(DataTablesOutput.View.class) + @RequestMapping(value = "/admin/data/awardtenders", method = RequestMethod.GET) + public DataTablesOutput getAwardTenderList(@Valid DataTablesInput input) { + CurrentUser usr = (CurrentUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); + int companyId = usr.getSelectedCompany().getId(); + + DataTablesOutput tenders = tenderDAO.findAll(input, null, (root, criteriaQuery, criteriaBuilder) -> { + return criteriaBuilder.and( + criteriaBuilder.equal(root.join("company").get("id"), companyId), + criteriaBuilder.or( + criteriaBuilder.equal(root.get("status"), 2), + criteriaBuilder.equal(root.get("status"), 3), + criteriaBuilder.equal(root.get("status"), 4) + ) + ); + }); + + return tenders; + } + + /** + * This method is used to give overall bid price comparison across different bids. + * + * @param id unique identifier of the tender + * @return String + * @throws JSONException if error when forming the JSON response + */ + @RequestMapping(value = "/admin/data/awardtenders/overallprice/{id}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) + public @ResponseBody String getTenderOverallPrice(@PathVariable(value="id") Integer id) throws JSONException { + JSONArray data = new JSONArray(); + + Tender tender = tenderDAO.findOne(id); + for (Bid b : tender.getBids()) { + JSONObject bidInfo = new JSONObject(); + bidInfo.put("y", b.getCompany().getName()); + bidInfo.put("a", b.getTotalAmount()); + data.put(bidInfo); + } + + return data.toString(); + } + + /** + * This method is used to give item price comparison across different bids. + * + * @param id unique identifier of the tender + * @return String + * @throws JSONException if error when forming the JSON response + */ + @RequestMapping(value = "/admin/data/awardtenders/itemPriceComparison/{id}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) + public @ResponseBody String getTenderItemPriceComparisson(@PathVariable(value="id") Integer id) throws JSONException { + JSONObject info = new JSONObject(); + JSONArray data = new JSONArray(); + JSONArray yAxis = new JSONArray(); + JSONArray label = new JSONArray(); + + HashSet yAxisSet = new HashSet(); + HashSet labelSet = new HashSet(); + + Tender tender = tenderDAO.findOne(id); + for (TenderItem i : tender.getItems()) { + JSONObject tenderItem = new JSONObject(); + tenderItem.put("y", i.getDescription()); + + for (Bid b : tender.getBids()) { + for (BidItem bi : b.getBidItems()) { + if (bi.getTenderItem().equals(i)) { + tenderItem.put(Integer.toString(b.getCompany().getId()), bi.getAmount()); + + if (!yAxisSet.contains(Integer.toString(b.getCompany().getId()))) { + yAxisSet.add(Integer.toString(b.getCompany().getId())); + yAxis.put(Integer.toString(b.getCompany().getId())); + } + + if (!labelSet.contains(b.getCompany().getName())) { + labelSet.add(b.getCompany().getName()); + label.put(b.getCompany().getName()); + } + } + } + } + + data.put(tenderItem); + } + + info.put("data", data); + info.put("yAxis", yAxis); + info.put("label", label); + + return info.toString(); + } + + /** + * This method is used to give overall evaluation score comparison across different bids. + * + * @param id unique identifier of the tender + * @return String + * @throws JSONException if error when forming the JSON response + */ + @RequestMapping(value = "/admin/data/awardtenders/overallScore/{id}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) + public @ResponseBody String getOverallScoreComparisson(@PathVariable(value="id") Integer id) throws JSONException { + JSONArray data = new JSONArray(); + + Tender tender = tenderDAO.findOne(id); + for (Bid b : tender.getBids()) { + JSONObject scoreInfo = new JSONObject(); + scoreInfo.put("y", b.getCompany().getName()); + scoreInfo.put("a", evaResDAO.getBidAverageEvaluationScore(b.getId())); + data.put(scoreInfo); + } + + return data.toString(); + } + + /** + * This method is used to give score comparison across different bids for 5 points evaluation criteria. + * + * @param id unique identifier of the tender + * @param criteriaId unique identifier of the evaluation criteria + * @return String + * @throws JSONException if error when forming the JSON response + */ + @RequestMapping(value = "/admin/data/awardtenders/criteriaScore/{id}/{criteriaId}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) + public @ResponseBody String getEvaluationCriteriaComparisson(@PathVariable(value="id") Integer id, + @PathVariable(value = "criteriaId") Integer criteriaId) throws JSONException { + JSONArray data = new JSONArray(); + + Tender tender = tenderDAO.findOne(id); + for (Bid b : tender.getBids()) { + JSONObject scoreInfo = new JSONObject(); + scoreInfo.put("y", b.getCompany().getName()); + scoreInfo.put("a", evaResDAO.getBidCriteriaAverageEvaluationScore(b.getId(), criteriaId)); + data.put(scoreInfo); + } + + return data.toString(); + } + + /** + * This method is used to give score comparison across different bids for 2 points evaluation criteria. + * + * @param id unique identifier of the tender + * @param criteriaId unique identifier of the evaluation criteria + * @return String + * @throws JSONException if error when forming the JSON response + */ + @RequestMapping(value = "/admin/data/awardtenders/dualCriteriaScore/{id}/{criteriaId}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) + public @ResponseBody String getEvaluationDualCriteriaComparisson(@PathVariable(value="id") Integer id, + @PathVariable(value = "criteriaId") Integer criteriaId) throws JSONException { + JSONArray data = new JSONArray(); + + Tender tender = tenderDAO.findOne(id); + for (Bid b : tender.getBids()) { + JSONObject scoreInfo = new JSONObject(); + scoreInfo.put("y", b.getCompany().getName()); + scoreInfo.put("yes", evaResDAO.getDualCriteriaEvaluationCount(b.getId(), criteriaId, 1)); + scoreInfo.put("no", evaResDAO.getDualCriteriaEvaluationCount(b.getId(), criteriaId, 2)); + data.put(scoreInfo); + } + + return data.toString(); } } diff --git a/src/main/java/com/chlorocode/tendertracker/web/data/TenderReportsDataController.java b/src/main/java/com/chlorocode/tendertracker/web/data/TenderReportsDataController.java new file mode 100644 index 0000000..14e9811 --- /dev/null +++ b/src/main/java/com/chlorocode/tendertracker/web/data/TenderReportsDataController.java @@ -0,0 +1,53 @@ +package com.chlorocode.tendertracker.web.data; + +import com.chlorocode.tendertracker.dao.TenderDAO; +import com.chlorocode.tendertracker.dao.entity.Tender; +import com.chlorocode.tendertracker.dao.entity.TenderVisit; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.*; + +/** + * REST controller for report. + */ +@RestController +public class TenderReportsDataController { + + private TenderDAO tenderDAO; + + /** + * Constructor. + * + * @param tenderDAO TenderDAO + */ + @Autowired + public TenderReportsDataController(TenderDAO tenderDAO){ + this.tenderDAO = tenderDAO; + } + + /** + * This method is used to provide tender visitor country data. + * + * @param id unique identifier of the data + * @return String + * @throws JSONException if error when forming the JSON response + */ + @RequestMapping(value = "/admin/data/report/countryVisitorList/{id}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) + public @ResponseBody + String getTenderCountryVisitorData(@PathVariable(value="id") Integer id) throws JSONException { + JSONArray data = new JSONArray(); + + Tender tender = tenderDAO.findOne(id); + for (TenderVisit v : tender.getTenderVisits()) { + JSONObject coordinate = new JSONObject(); + coordinate.put("lat", v.getLat()); + coordinate.put("lon", v.getLon()); + data.put(coordinate); + } + + return data.toString(); + } +} diff --git a/src/main/java/com/chlorocode/tendertracker/web/data/UserDataController.java b/src/main/java/com/chlorocode/tendertracker/web/data/UserDataController.java index 204e030..9da9565 100644 --- a/src/main/java/com/chlorocode/tendertracker/web/data/UserDataController.java +++ b/src/main/java/com/chlorocode/tendertracker/web/data/UserDataController.java @@ -15,17 +15,29 @@ import javax.validation.Valid; /** - * Created by andy on 16/7/2017. + * REST controller for user. */ @RestController public class UserDataController { + private UserDataDAO userDao; + /** + * Constructor. + * + * @param UserDAO UserDataDAO + */ @Autowired public UserDataController(UserDataDAO UserDAO) { this.userDao = UserDAO; } + /** + * This method is used to search company user. + * + * @param input data table search input + * @return data table output + */ @JsonView(DataTablesOutput.View.class) @RequestMapping(value = "/admin/data/companyUser", method = RequestMethod.GET) public DataTablesOutput getUserData(@Valid DataTablesInput input) { diff --git a/src/main/java/com/chlorocode/tendertracker/web/handler/CustomAuthenticationFailureHandler.java b/src/main/java/com/chlorocode/tendertracker/web/handler/CustomAuthenticationFailureHandler.java index c5f6589..accbce2 100644 --- a/src/main/java/com/chlorocode/tendertracker/web/handler/CustomAuthenticationFailureHandler.java +++ b/src/main/java/com/chlorocode/tendertracker/web/handler/CustomAuthenticationFailureHandler.java @@ -10,9 +10,21 @@ import javax.servlet.http.HttpServletResponse; import java.io.IOException; +/** + * This class is used customize the authentication failure. + */ @Component("authenticationFailureHandler") public class CustomAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler { + /** + * This method will be fired when the authentication failure. + * + * @param request HttpServletRequest + * @param response HttpServletResponse + * @param exception AuthenticationException + * @throws IOException IOException + * @throws ServletException ServletException + */ @Override public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException { setDefaultFailureUrl("/login?error=true"); diff --git a/src/main/java/com/chlorocode/tendertracker/web/listener/AuthenticationFailureEventListener.java b/src/main/java/com/chlorocode/tendertracker/web/listener/AuthenticationFailureEventListener.java index 1dcbcee..a3952d8 100644 --- a/src/main/java/com/chlorocode/tendertracker/web/listener/AuthenticationFailureEventListener.java +++ b/src/main/java/com/chlorocode/tendertracker/web/listener/AuthenticationFailureEventListener.java @@ -5,9 +5,11 @@ import org.springframework.context.ApplicationListener; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.authentication.event.AuthenticationFailureBadCredentialsEvent; -import org.springframework.security.web.authentication.WebAuthenticationDetails; import org.springframework.stereotype.Component; +/** + * This class is used to intercept the authentication login failure process. + */ @Component public class AuthenticationFailureEventListener implements ApplicationListener { @@ -15,6 +17,13 @@ public class AuthenticationFailureEventListener @Autowired private LoginAttemptService loginAttemptService; + /** + * This method will be fired when user's authentication process is fail. + * When authentication is failure, application will increase the attempt count of user to Max. + * If maximum amount of attempt is exceed, application will lock the user account. + * + * @param e AuthenticationFailureBadCredentialsEvent + */ public void onApplicationEvent(AuthenticationFailureBadCredentialsEvent e) { UsernamePasswordAuthenticationToken auth = (UsernamePasswordAuthenticationToken) e.getAuthentication(); String email = (String) auth.getPrincipal(); diff --git a/src/main/java/com/chlorocode/tendertracker/web/listener/AuthenticationSuccessEventListener.java b/src/main/java/com/chlorocode/tendertracker/web/listener/AuthenticationSuccessEventListener.java index 8357dc8..18aa262 100644 --- a/src/main/java/com/chlorocode/tendertracker/web/listener/AuthenticationSuccessEventListener.java +++ b/src/main/java/com/chlorocode/tendertracker/web/listener/AuthenticationSuccessEventListener.java @@ -6,9 +6,11 @@ import org.springframework.context.ApplicationListener; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.authentication.event.AuthenticationSuccessEvent; -import org.springframework.security.web.authentication.WebAuthenticationDetails; import org.springframework.stereotype.Component; +/** + * This class is used to intercept the authentication login success process. + */ @Component public class AuthenticationSuccessEventListener implements ApplicationListener { @@ -16,6 +18,12 @@ public class AuthenticationSuccessEventListener @Autowired private LoginAttemptService loginAttemptService; + /** + * This method will be fired when user's authentication process is success. + * When authentication is success, application will reset the attempt count of user account to 0. + * + * @param e AuthenticationSuccessEvent + */ public void onApplicationEvent(AuthenticationSuccessEvent e) { UsernamePasswordAuthenticationToken auth = (UsernamePasswordAuthenticationToken) e.getAuthentication(); CurrentUser user = (CurrentUser) auth.getPrincipal(); diff --git a/src/main/java/com/chlorocode/tendertracker/web/sysadm/CompanySysAdmController.java b/src/main/java/com/chlorocode/tendertracker/web/sysadm/CompanySysAdmController.java index 77e5c98..6ae413f 100644 --- a/src/main/java/com/chlorocode/tendertracker/web/sysadm/CompanySysAdmController.java +++ b/src/main/java/com/chlorocode/tendertracker/web/sysadm/CompanySysAdmController.java @@ -2,39 +2,136 @@ import com.chlorocode.tendertracker.dao.dto.AlertDTO; import com.chlorocode.tendertracker.dao.dto.CompanyRegistrationDetailsDTO; -import com.chlorocode.tendertracker.dao.entity.CurrentUser; -import com.chlorocode.tendertracker.dao.entity.UenEntity; +import com.chlorocode.tendertracker.dao.dto.ProductUpdateDTO; +import com.chlorocode.tendertracker.dao.entity.*; import com.chlorocode.tendertracker.exception.ApplicationException; import com.chlorocode.tendertracker.exception.ResourceNotFoundException; -import com.chlorocode.tendertracker.service.CompanyService; -import com.chlorocode.tendertracker.service.UenEntityService; +import com.chlorocode.tendertracker.service.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; +import org.springframework.ui.ModelMap; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.servlet.mvc.support.RedirectAttributes; +import java.util.List; + +/** + * Controller for system administrator panel. + */ @Controller public class CompanySysAdmController { private CompanyService companyService; private UenEntityService uenEntService; + private ProductService productService; + private CodeValueService codeValueService; + private TenderService tenderService; + private S3Wrapper s3Service; + private UserService userService; + /** + * Constructor. + * + * @param companyService CompanyService + * @param uenEntService UenEntityService + * @param productService ProductService + * @param codeValueService CodeValueService + * @param tenderService TenderService + * @param s3Service S3Service + * @param userService UserService + */ @Autowired - public CompanySysAdmController(CompanyService companyService, UenEntityService uenEntService) { + public CompanySysAdmController(CompanyService companyService, UenEntityService uenEntService,ProductService productService,CodeValueService codeValueService + ,TenderService tenderService,S3Wrapper s3Service,UserService userService) { this.companyService = companyService; this.uenEntService = uenEntService; + this.productService = productService; + this.codeValueService = codeValueService; + this.tenderService = tenderService; + this.s3Service = s3Service; + this.userService = userService; } + /** + * This method is used to display company registration list page. + * + * @return String + */ @GetMapping("/sysadm/companyRegistration") public String showCompanyRegistration() { return "admin/sysadm/companyRegistrationView"; } + /** + * This method is used to display page containing all approved / rejected companies. + * + * @return String + */ + @GetMapping("/sysadm/companyRegistrationList") + public String showCompanyRegistrationList() { + return "admin/sysadm/companyInfoView"; + } + + /** + * This method is used to display page containing all tenders. + * + * @return String + */ + @GetMapping("/sysadm/tender") + public String showTenderList() { + return "admin/sysadm/tenderList"; + } + + /** + * This method is used to display company details page. + * + * @param id unique identifier of the company + * @param model Model + * @return String + */ + @GetMapping("/sysadm/companyInfo/{id}") + public String showcompanyInfo(@PathVariable(value="id") Integer id, Model model) { + CompanyRegistrationDetailsDTO companyRegistration = companyService.findCompanyRegistrationById(id); + + if (companyRegistration == null) { + throw new ResourceNotFoundException(); + } + + model.addAttribute("reg", companyRegistration); + + UenEntity uenEnt = uenEntService.findByUen(companyRegistration.getUen()); + if(uenEnt == null){ + model.addAttribute("uenInvalidLabel","Unverified UEN"); + }else{ + model.addAttribute("uenValidLabel", "UEN Verified"); + } + + if(companyRegistration.getStatus().equalsIgnoreCase("Approved")){ + model.addAttribute("approved","Approved"); + }else if(companyRegistration.getStatus().equalsIgnoreCase("Rejected")){ + model.addAttribute("rejected","Rejected"); + } + + if(companyRegistration.isActive()){ + model.addAttribute("active","Active"); + }else if(!companyRegistration.isActive()){ + model.addAttribute("blacklisted","Blacklisted"); + } + return "admin/sysadm/companyDetail"; + } + + /** + * This method is used to show company registration details page. + * + * @param id unique identifier of the company + * @param model Model + * @return String + */ @GetMapping("/sysadm/companyRegistration/{id}") public String showCompanyRegistrationDetail(@PathVariable(value="id") Integer id, Model model) { CompanyRegistrationDetailsDTO companyRegistration = companyService.findCompanyRegistrationById(id); @@ -55,6 +152,60 @@ public String showCompanyRegistrationDetail(@PathVariable(value="id") Integer id return "admin/sysadm/companyRegistrationDetail"; } + /** + * This method is used to blacklist / remove blacklist from a company. + * + * @param id unique identifier of the company + * @param action action to indicate blacklist / unblacklist company + * @param redirectAttrs RedirectAttributes + * @return String + */ + @PostMapping("/sysadm/blacklistCompany") + public String blacklistCompany(@RequestParam("id") int id, @RequestParam("action") String action, + RedirectAttributes redirectAttrs) { + CurrentUser usr = (CurrentUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); + + try{ + if (action.equals("blacklist")) { + boolean result = companyService.blacklistCompany(id, usr.getId()); + if(result){ + AlertDTO alert = new AlertDTO(AlertDTO.AlertType.SUCCESS, + "Company blacklisted Successful"); + redirectAttrs.addFlashAttribute("alert", alert); + }else{ + AlertDTO alert = new AlertDTO(AlertDTO.AlertType.SUCCESS, + "Something went wrong. Cannot blacklisted the company"); + redirectAttrs.addFlashAttribute("alert", alert); + } + } else { + boolean result = companyService.unblacklistCompany(id, usr.getId()); + if (result) { + AlertDTO alert = new AlertDTO(AlertDTO.AlertType.SUCCESS, + "Company unblacklisted Successful"); + redirectAttrs.addFlashAttribute("alert", alert); + } else { + AlertDTO alert = new AlertDTO(AlertDTO.AlertType.SUCCESS, + "Something went wrong. Cannot blacklisted the company"); + redirectAttrs.addFlashAttribute("alert", alert); + } + } + }catch (ApplicationException ex){ + AlertDTO alert = new AlertDTO(AlertDTO.AlertType.DANGER, + "Error encountered: " + ex.getMessage()); + redirectAttrs.addFlashAttribute("alert", alert); + } + + return "redirect:/sysadm/companyRegistrationList"; + } + + /** + * This method is used to approve / reject company registration. + * + * @param id unique identifier of the company + * @param action action to indicate approve / reject company + * @param redirectAttrs RedirectAttributes + * @return String + */ @PostMapping("/sysadm/companyRegistration") public String approveRejectCompanyRegistration(@RequestParam("id") int id, @RequestParam("action") String action, RedirectAttributes redirectAttrs) { @@ -82,4 +233,99 @@ public String approveRejectCompanyRegistration(@RequestParam("id") int id, @Requ return "redirect:/sysadm/companyRegistration"; } + + /** + * This method is used to display product listing page. + * + * @return String + */ + @GetMapping("/sysadm/product") + public String showAllProduct() { + return "admin/sysadm/productList"; + } + + /** + * This method is used to display product details page. + * + * @param id unique identifier of the product + * @param model ModelMap + * @return String + */ + @GetMapping("/sysadmin/product/view/{id}") + public String showProductPage(@PathVariable(value = "id") Integer id, ModelMap model) { + Product product = productService.findById(id); + if (product == null) { + return "redirect:/admin/product"; + } + + ProductUpdateDTO productDTO = new ProductUpdateDTO(); + productDTO.setProductCode(product.getProductCode()); + productDTO.setCategory(product.getCategory()); + productDTO.setDescription(product.getDescription()); + productDTO.setPrice(product.getPrice()); + productDTO.setTitle(product.getTitle()); + productDTO.setType(product.getType()); + productDTO.setPublished(product.isPublish()); + + List lstCode = codeValueService.getByType("product_category"); + for(int i = 0; i < lstCode.size(); i++){ + CodeValue code = lstCode.get(i); + if(code.getCode() == productDTO.getCategory()){ + productDTO.setCategoryDescription(code.getDescription()); + break; + } + } + model.addAttribute("product", productDTO); + model.addAttribute("productCategory", codeValueService.getByType("product_category")); + + return "admin/sysadm/productFormView"; + } + + /** + * This method is used to blacklist a product. + * + * @param id unique identifier of the product + * @param model ModelMap + * @return String + */ + @PostMapping("/sysadmin/product/blacklist") + public String updateTenderClarificationResponse(@RequestParam("id") int id, ModelMap model){ + + Product product = productService.blacklistProduct(id); + if(product == null){ + AlertDTO alert = new AlertDTO(AlertDTO.AlertType.DANGER, + "Failed to blacklist product. Please contact administrator"); + model.addAttribute("alert", alert); + }else{ + AlertDTO alert = new AlertDTO(AlertDTO.AlertType.SUCCESS, + "The product is successfully blacklisted"); + model.addAttribute("alert", alert); + } + + return "admin/sysadm/productList"; + } + + /** + * This method is used to view tender details. + * + * @param id uique identifier of the tender + * @param model ModelMap + * @return String + */ + @GetMapping("/sysadmin/tender/{id}") + public String showTenderDetails(@PathVariable(value="id") Integer id, ModelMap model) { + Tender tender = tenderService.findById(id); + if (tender == null) { + return "redirect:/admin/tender"; + } + + User user = userService.findById(tender.getCreatedBy()); + + model.addAttribute("tender", tender); + model.addAttribute("tenderType", codeValueService.getDescription("tender_type", tender.getTenderType())); + model.addAttribute("codeValueService", codeValueService); + model.addAttribute("s3Service", s3Service); + model.addAttribute("createdBy", user.getName()); + return "admin/sysadm/tenderViewSys"; + } } diff --git a/src/main/java/com/chlorocode/tendertracker/web/userprofile/UserProfileController.java b/src/main/java/com/chlorocode/tendertracker/web/userprofile/UserProfileController.java index 226367f..f01112f 100644 --- a/src/main/java/com/chlorocode/tendertracker/web/userprofile/UserProfileController.java +++ b/src/main/java/com/chlorocode/tendertracker/web/userprofile/UserProfileController.java @@ -2,19 +2,17 @@ import com.chlorocode.tendertracker.dao.dto.AlertDTO; import com.chlorocode.tendertracker.dao.dto.ChangePasswordDTO; -import com.chlorocode.tendertracker.dao.dto.TenderClarificationDTO; import com.chlorocode.tendertracker.dao.dto.UserProfileDTO; import com.chlorocode.tendertracker.dao.entity.*; import com.chlorocode.tendertracker.service.CodeValueService; import com.chlorocode.tendertracker.service.CompanyService; -import com.chlorocode.tendertracker.service.TenderService; +import com.chlorocode.tendertracker.service.TenderSubscriptionService; import com.chlorocode.tendertracker.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Controller; import org.springframework.ui.ModelMap; import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestParam; @@ -28,17 +26,18 @@ @Controller public class UserProfileController { private UserService userService; - private TenderService tenderService; private CodeValueService codeValueService; private CompanyService companyService; + private TenderSubscriptionService tenderSubscriptionService; @Autowired - public UserProfileController(UserService userService,TenderService tenderService, CodeValueService codeValueService,CompanyService companyService) + public UserProfileController(UserService userService, CodeValueService codeValueService + , CompanyService companyService, TenderSubscriptionService tenderSubscriptionService) { this.userService = userService; - this.tenderService = tenderService; this.codeValueService = codeValueService; this.companyService = companyService; + this.tenderSubscriptionService = tenderSubscriptionService; } @GetMapping("/user/profile") @@ -73,7 +72,7 @@ public String showUserProfilePage(ModelMap model){ } usrDto.setIdNo(usr.getIdNo()); - List lstBokkmark = tenderService.findTenderBookmarkByUserId(usr.getId()); + List lstBokkmark = tenderSubscriptionService.findTenderBookmarkByUserId(usr.getId()); List lstCompany = companyService.findCompanyByCreatedBy(currentUser.getId()); @@ -124,7 +123,7 @@ public String updateUserProfilePage(ModelMap model,@Valid UserProfileDTO form, List lstCompany = companyService.findCompanyByCreatedBy(userId); model.addAttribute("companyList",lstCompany); - List lstBokkmark = tenderService.findTenderBookmarkByUserId(userId); + List lstBokkmark = tenderSubscriptionService.findTenderBookmarkByUserId(userId); model.addAttribute("bookmarkTenderList",lstBokkmark); ChangePasswordDTO pwd = new ChangePasswordDTO(); model.addAttribute("passwordDto",pwd); @@ -137,7 +136,7 @@ public String removeTenderBookmark(ModelMap model, CurrentUser currentUser = (CurrentUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); - tenderService.removeTenderBookmark(tenderId, currentUser.getUser().getId()); + tenderSubscriptionService.removeTenderBookmark(tenderId, currentUser.getUser().getId()); User usr = userService.findById(currentUser.getId()); if(usr == null){ @@ -162,7 +161,7 @@ public String removeTenderBookmark(ModelMap model, } } - List lstBokkmark = tenderService.findTenderBookmarkByUserId(usr.getId()); + List lstBokkmark = tenderSubscriptionService.findTenderBookmarkByUserId(usr.getId()); List lstCompany = companyService.findCompanyByCreatedBy(currentUser.getId()); model.addAttribute("companyList",lstCompany); @@ -209,7 +208,7 @@ public String updateUserPassword(ModelMap model,@Valid ChangePasswordDTO form, } ChangePasswordDTO pwd = new ChangePasswordDTO(); - List lstBokkmark = tenderService.findTenderBookmarkByUserId(userId); + List lstBokkmark = tenderSubscriptionService.findTenderBookmarkByUserId(userId); List lstCompany = companyService.findCompanyByCreatedBy(userId); model.addAttribute("companyList",lstCompany); diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index f27f599..b9be7eb 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1,7 +1,7 @@ server.port = 8080 application.timezone=Asia/Singapore -spring.datasource.url=jdbc:mysql://tender-tracker.ctro7ub99vlk.ap-southeast-1.rds.amazonaws.com/tender_tracker?verifyServerCertificate=false&useSSL=false&requireSSL=false +spring.datasource.url=jdbc:mysql://tender-tracker.ctro7ub99vlk.ap-southeast-1.rds.amazonaws.com/tender_tracker?verifyServerCertificate=false&useSSL=false&requireSSL=false&zeroDateTimeBehavior=convertToNull spring.datasource.username=root spring.datasource.password=tendertracker spring.datasource.driver-class-name=com.mysql.jdbc.Driver @@ -22,12 +22,24 @@ cloud.aws.s3.bucket=tender-tracker # Email subject mail.subOTP=[TenderTracker] Please reset your password + mail.subWelcome=Welcome to Tender Tracker. mail.subUpdateTender=[TenderTracker] Tender has been updated. mail.subAddCorrigendum=[TenderTracker] New corrigendum added to tender. mail.subCreateTender=[TenderTracker] New tender created. +mail.subClosedTender=[TenderTracker] Tender closed and ready for evaluation. mail.subCompanyReview=[TenderTracker] Your company registration has been reviewed. mail.subCompanyRegistered=[TenderTracker] Company registration submitted. +mail.subCompanyBlacklisted=[TenderTracker] Your company has been blacklisted. +mail.subMilestoneApproach=[TenderTracker] Milestone is approaching +mail.subAppealCreate=[TenderTracker] New appeal created +mail.subAppealUpdate=[TenderTracker] Appeal has been updated +mail.subAppealAccepted=[TenderTracker] Appeal has been accepted +mail.subAppealRejected=[TenderTracker] Appeal has been rejected +mail.subTenderAwarded=[TenderTracker] Tender has been awarded + + + # Email template path mail.templateOTP=mail_templates/otp_mail_template.html @@ -39,7 +51,18 @@ mail.templateCompanyApproved=mail_templates/company_approve_mail_template.html mail.templateCompanyRejected=mail_templates/company_reject_mail_template.html mail.templateCompanyRegistered=mail_templates/company_registered_template.html -mail.from.account=mark.lauw@chlorocode.com +mail.templateCompanyBlacklisted=mail_templates/company_blacklist_mail_template.html + +mail.templateMilestoneApproach=mail_templates/milestone_approach_mail_template.html +mail.templateAppealCreate=mail_templates/create_appeal_mail_template.html +mail.templateAppealUpdate=mail_templates/update_appeal_mail_template.html +mail.templateAppealAccepted=mail_templates/accepted_appeal_mail_template.html +mail.templateAppealRejected=mail_templates/rejected_appeal_mail_template.html +mail.templateTenderAwarded=mail_templates/award_tender_mail_template.html +mail.templateClosedTender=mail_templates/closed_tender_mail_template.html + + +mail.from.account=tendertracker.chlorocode@gmail.com # Email notification # Gmail SMTP Properties @@ -58,4 +81,8 @@ spring.mail.properties.mail.transport.protocol=smtp spring.mail.properties.mail.smtp.port=25 spring.mail.properties.mail.smtp.auth=true spring.mail.properties.mail.smtp.starttls.enable=true -spring.mail.properties.mail.smtp.starttls.required=true \ No newline at end of file +spring.mail.properties.mail.smtp.starttls.required=true + +# Tender Crawler HTTP Auth +crawler.username=crawler +crawler.password=crawler2017 \ No newline at end of file diff --git a/src/main/resources/mail_templates/accepted_appeal_mail_template.html b/src/main/resources/mail_templates/accepted_appeal_mail_template.html new file mode 100644 index 0000000..54fb47b --- /dev/null +++ b/src/main/resources/mail_templates/accepted_appeal_mail_template.html @@ -0,0 +1,14 @@ + + +

"PARAM0" accepted appeal for tender "PARAM1"

+

Please see more information on following link. +
+ "http://tendertracker.chlorocode.com/tender/PARAM3" +

+

+ Regards, +
+ Tender Tracker +

+ + diff --git a/src/main/resources/mail_templates/award_tender_mail_template.html b/src/main/resources/mail_templates/award_tender_mail_template.html new file mode 100644 index 0000000..f0e9e6a --- /dev/null +++ b/src/main/resources/mail_templates/award_tender_mail_template.html @@ -0,0 +1,14 @@ + + +

"PARAM0" company has been award the Tender "PARAM1"

+

Please see more information on following link. +
+ "http://tendertracker.chlorocode.com/tender/PARAM3" +

+

+ Regards, +
+ Tender Tracker +

+ + diff --git a/src/main/resources/mail_templates/closed_tender_mail_template.html b/src/main/resources/mail_templates/closed_tender_mail_template.html new file mode 100644 index 0000000..15f7b01 --- /dev/null +++ b/src/main/resources/mail_templates/closed_tender_mail_template.html @@ -0,0 +1,14 @@ + + +

Tender "PARAM0" has been closed and ready for evaluation.

+

Please see more information on following link. +
+ "http://tendertracker.chlorocode.com/tender/PARAM2" +

+

+ Regards, +
+ Tender Tracker +

+ + diff --git a/src/main/resources/mail_templates/company_appeal_processed.html b/src/main/resources/mail_templates/company_appeal_processed.html new file mode 100644 index 0000000..cca70cb --- /dev/null +++ b/src/main/resources/mail_templates/company_appeal_processed.html @@ -0,0 +1,6 @@ + + +

Sorry, your tender appeal had been accepted and processed bt tenderer preparer. Tender preparer will contact you shortly

+

Regards,
Tender Tracker

+ + \ No newline at end of file diff --git a/src/main/resources/mail_templates/company_appeal_rejected.html b/src/main/resources/mail_templates/company_appeal_rejected.html new file mode 100644 index 0000000..dbf5494 --- /dev/null +++ b/src/main/resources/mail_templates/company_appeal_rejected.html @@ -0,0 +1,6 @@ + + +

Sorry, your tender appeal had been rejected bt tender preparer

+

Regards,
Tender Tracker

+ + \ No newline at end of file diff --git a/src/main/resources/mail_templates/company_blacklist_mail_template.html b/src/main/resources/mail_templates/company_blacklist_mail_template.html new file mode 100644 index 0000000..fe15b87 --- /dev/null +++ b/src/main/resources/mail_templates/company_blacklist_mail_template.html @@ -0,0 +1,6 @@ + + +

Sorry, your company "PARAM0" had been blacklisted by Administrator. Kindly please contact Administrator for more details

+

Regards,
Tender Tracker

+ + \ No newline at end of file diff --git a/src/main/resources/mail_templates/company_submit_appeal.html b/src/main/resources/mail_templates/company_submit_appeal.html new file mode 100644 index 0000000..732aa34 --- /dev/null +++ b/src/main/resources/mail_templates/company_submit_appeal.html @@ -0,0 +1,6 @@ + + +

your company "PARAM0" had been submitted the tender appeal result to Administrator. Kindly please waiting the status update from tender preparer

+

Regards,
Tender Tracker

+ + \ No newline at end of file diff --git a/src/main/resources/mail_templates/create_appeal_mail_template.html b/src/main/resources/mail_templates/create_appeal_mail_template.html new file mode 100644 index 0000000..5fc90b5 --- /dev/null +++ b/src/main/resources/mail_templates/create_appeal_mail_template.html @@ -0,0 +1,14 @@ + + +

"PARAM0" create appeal for tender "PARAM1"

+

Please see more information on following link. +
+ "http://tendertracker.chlorocode.com/tender/PARAM3" +

+

+ Regards, +
+ Tender Tracker +

+ + diff --git a/src/main/resources/mail_templates/milestone_approach_mail_template.html b/src/main/resources/mail_templates/milestone_approach_mail_template.html new file mode 100644 index 0000000..afac090 --- /dev/null +++ b/src/main/resources/mail_templates/milestone_approach_mail_template.html @@ -0,0 +1,16 @@ + + +

Milestone "PARAM0" from Tender "PARAM1" is approaching.

+

Due Date : "PARAM2"

+

Status : "PARAM3"

+

Please see more information on following link. +
+ "http://tendertracker.chlorocode.com/tender/PARAM5" +

+

+ Regards, +
+ Tender Tracker +

+ + diff --git a/src/main/resources/mail_templates/rejected_appeal_mail_template.html b/src/main/resources/mail_templates/rejected_appeal_mail_template.html new file mode 100644 index 0000000..0a601e8 --- /dev/null +++ b/src/main/resources/mail_templates/rejected_appeal_mail_template.html @@ -0,0 +1,14 @@ + + +

"PARAM0" rejected appeal for tender "PARAM1"

+

Please see more information on following link. +
+ "http://tendertracker.chlorocode.com/tender/PARAM3" +

+

+ Regards, +
+ Tender Tracker +

+ + diff --git a/src/main/resources/mail_templates/update_appeal_mail_template.html b/src/main/resources/mail_templates/update_appeal_mail_template.html new file mode 100644 index 0000000..a037d07 --- /dev/null +++ b/src/main/resources/mail_templates/update_appeal_mail_template.html @@ -0,0 +1,14 @@ + + +

"PARAM0" update appeal for tender "PARAM1"

+

Please see more information on following link. +
+ "http://tendertracker.chlorocode.com/tender/PARAM3" +

+

+ Regards, +
+ Tender Tracker +

+ + diff --git a/src/main/resources/static/assets/admin/plugins/bootstrap-tagsinput/bootstrap-tagsinput.css b/src/main/resources/static/assets/admin/plugins/bootstrap-tagsinput/bootstrap-tagsinput.css new file mode 100644 index 0000000..0b03251 --- /dev/null +++ b/src/main/resources/static/assets/admin/plugins/bootstrap-tagsinput/bootstrap-tagsinput.css @@ -0,0 +1,104 @@ +.bootstrap-tagsinput { + background-color: #fff; + border: 1px solid #ccc; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + display: inline-block; + padding: 4px 6px; + color: #555; + vertical-align: middle; + border-radius: 4px; + max-width: 100%; + line-height: 22px; + cursor: text; +} +.bootstrap-tagsinput input { + border: none; + box-shadow: none; + outline: none; + background-color: transparent; + padding: 0 6px; + margin: 0; + width: auto; + max-width: inherit; +} +.bootstrap-tagsinput.form-control input::-moz-placeholder { + color: #777; + opacity: 1; +} +.bootstrap-tagsinput.form-control input:-ms-input-placeholder { + color: #777; +} +.bootstrap-tagsinput.form-control input::-webkit-input-placeholder { + color: #777; +} +.bootstrap-tagsinput input:focus { + border: none; + box-shadow: none; +} +.bootstrap-tagsinput .tag { + margin-right: 2px; + color: white; +} +.bootstrap-tagsinput .tag [data-role="remove"] { + margin-left: 8px; + cursor: pointer; +} +.bootstrap-tagsinput .tag [data-role="remove"]:after { + content: "x"; + padding: 0px 2px; +} +.bootstrap-tagsinput .tag [data-role="remove"]:hover { + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); +} +.bootstrap-tagsinput .tag [data-role="remove"]:hover:active { + box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); +} +.twitter-typeahead .tt-query, +.twitter-typeahead .tt-hint { + margin-bottom: 0; +} + +.twitter-typeahead .tt-hint +{ + display: none; +} + +.tt-menu { + position: absolute; + top: 100%; + left: 0; + z-index: 1000; + display: none; + float: left; + min-width: 160px; + padding: 5px 0; + margin: 2px 0 0; + list-style: none; + font-size: 14px; + background-color: #ffffff; + border: 1px solid #cccccc; + border: 1px solid rgba(0, 0, 0, 0.15); + border-radius: 4px; + -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175); + box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175); + background-clip: padding-box; + cursor: pointer; +} + +.tt-suggestion { + display: block; + padding: 3px 20px; + clear: both; + font-weight: normal; + line-height: 1.428571429; + color: #333333; + white-space: nowrap; +} + +.tt-suggestion:hover, +.tt-suggestion:focus { + color: #ffffff; + text-decoration: none; + outline: 0; + background-color: #428bca; +} diff --git a/src/main/resources/static/assets/admin/plugins/bootstrap-tagsinput/bootstrap-tagsinput.js b/src/main/resources/static/assets/admin/plugins/bootstrap-tagsinput/bootstrap-tagsinput.js new file mode 100644 index 0000000..2b403f7 --- /dev/null +++ b/src/main/resources/static/assets/admin/plugins/bootstrap-tagsinput/bootstrap-tagsinput.js @@ -0,0 +1,646 @@ +(function ($) { + "use strict"; + + var defaultOptions = { + tagClass: function(item) { + return 'label label-info'; + }, + itemValue: function(item) { + return item ? item.toString() : item; + }, + itemText: function(item) { + return this.itemValue(item); + }, + itemTitle: function(item) { + return null; + }, + freeInput: true, + addOnBlur: true, + maxTags: undefined, + maxChars: undefined, + confirmKeys: [13, 44], + delimiter: ',', + delimiterRegex: null, + cancelConfirmKeysOnEmpty: true, + onTagExists: function(item, $tag) { + $tag.hide().fadeIn(); + }, + trimValue: false, + allowDuplicates: false + }; + + /** + * Constructor function + */ + function TagsInput(element, options) { + this.itemsArray = []; + + this.$element = $(element); + this.$element.hide(); + + this.isSelect = (element.tagName === 'SELECT'); + this.multiple = (this.isSelect && element.hasAttribute('multiple')); + this.objectItems = options && options.itemValue; + this.placeholderText = element.hasAttribute('placeholder') ? this.$element.attr('placeholder') : ''; + this.inputSize = Math.max(1, this.placeholderText.length); + + this.$container = $('
'); + this.$input = $('').appendTo(this.$container); + + this.$element.before(this.$container); + + this.build(options); + } + + TagsInput.prototype = { + constructor: TagsInput, + + /** + * Adds the given item as a new tag. Pass true to dontPushVal to prevent + * updating the elements val() + */ + add: function(item, dontPushVal, options) { + var self = this; + + if (self.options.maxTags && self.itemsArray.length >= self.options.maxTags) + return; + + // Ignore falsey values, except false + if (item !== false && !item) + return; + + // Trim value + if (typeof item === "string" && self.options.trimValue) { + item = $.trim(item); + } + + // Throw an error when trying to add an object while the itemValue option was not set + if (typeof item === "object" && !self.objectItems) + throw("Can't add objects when itemValue option is not set"); + + // Ignore strings only containg whitespace + if (item.toString().match(/^\s*$/)) + return; + + // If SELECT but not multiple, remove current tag + if (self.isSelect && !self.multiple && self.itemsArray.length > 0) + self.remove(self.itemsArray[0]); + + if (typeof item === "string" && this.$element[0].tagName === 'INPUT') { + var delimiter = (self.options.delimiterRegex) ? self.options.delimiterRegex : self.options.delimiter; + var items = item.split(delimiter); + if (items.length > 1) { + for (var i = 0; i < items.length; i++) { + this.add(items[i], true); + } + + if (!dontPushVal) + self.pushVal(); + return; + } + } + + var itemValue = self.options.itemValue(item), + itemText = self.options.itemText(item), + tagClass = self.options.tagClass(item), + itemTitle = self.options.itemTitle(item); + + // Ignore items allready added + var existing = $.grep(self.itemsArray, function(item) { return self.options.itemValue(item) === itemValue; } )[0]; + if (existing && !self.options.allowDuplicates) { + // Invoke onTagExists + if (self.options.onTagExists) { + var $existingTag = $(".tag", self.$container).filter(function() { return $(this).data("item") === existing; }); + self.options.onTagExists(item, $existingTag); + } + return; + } + + // if length greater than limit + if (self.items().toString().length + item.length + 1 > self.options.maxInputLength) + return; + + // raise beforeItemAdd arg + var beforeItemAddEvent = $.Event('beforeItemAdd', { item: item, cancel: false, options: options}); + self.$element.trigger(beforeItemAddEvent); + if (beforeItemAddEvent.cancel) + return; + + // register item in internal array and map + self.itemsArray.push(item); + + // add a tag element + + var $tag = $('' + htmlEncode(itemText) + ''); + $tag.data('item', item); + self.findInputWrapper().before($tag); + $tag.after(' '); + + // add