diff --git a/pom.xml b/pom.xml index 99cf0888..23317f49 100644 --- a/pom.xml +++ b/pom.xml @@ -139,6 +139,69 @@ jackson-databind 2.13.0 + + org.projectlombok + lombok + 1.18.24 + + + + + com.mercadopago + sdk-java + 2.1.20 + + + + com.itextpdf + itext7-core + 7.2.0 + + + + com.sun.mail + javax.mail + 1.6.2 + + + + + org.apache.xmlgraphics + batik-transcoder + 1.14 + + + xalan + xalan + + + + + + + com.google.zxing + core + 3.4.1 + + + + com.google.zxing + javase + 3.4.1 + + + + + org.apache.xmlgraphics + fop + 2.6 + + + xalan + xalan + + + diff --git a/src/main/java/br/edu/utfpr/servicebook/controller/ClientController.java b/src/main/java/br/edu/utfpr/servicebook/controller/ClientController.java index e4966ad3..ded53a38 100644 --- a/src/main/java/br/edu/utfpr/servicebook/controller/ClientController.java +++ b/src/main/java/br/edu/utfpr/servicebook/controller/ClientController.java @@ -16,9 +16,13 @@ import br.edu.utfpr.servicebook.util.pagination.PaginationUtil; import br.edu.utfpr.servicebook.util.UserTemplateInfo; import br.edu.utfpr.servicebook.util.TemplateUtil; +import com.cloudinary.Cloudinary; +import com.cloudinary.utils.ObjectUtils; +import org.apache.batik.transcoder.TranscoderException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Sort; @@ -31,11 +35,18 @@ import javax.annotation.security.RolesAllowed; import javax.persistence.EntityNotFoundException; import javax.servlet.http.HttpServletRequest; +import javax.xml.transform.TransformerException; +import java.io.File; import java.io.IOException; +import java.text.SimpleDateFormat; import java.time.LocalDate; -import java.util.List; -import java.util.Optional; +import java.util.*; import java.util.stream.Collectors; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.BindingResult; +import com.google.zxing.WriterException; +import org.apache.batik.transcoder.TranscoderException; +import org.apache.fop.configuration.ConfigurationException; @RequestMapping("/minha-conta/cliente") @Controller @@ -104,7 +115,32 @@ public class ClientController { @Autowired private ProfessionalMapper professionalMapper; + @Autowired + private PaymentService paymentService; + + @Autowired + private PaymentMapper paymentMapper; + + @Autowired + private PaymentVoucherService paymentVoucherService; + + @Autowired + private PaymentVoucherMapper paymentVoucherMapper; + + @Autowired + private PaymentJobService paymentJobService; + + @Autowired + private PaymentJobMapper paymentJobMapper; + + @Autowired + private Cloudinary cloudinary; + + @Autowired + private ProfessionalServiceOfferingService professionalServiceOfferingService; + @Value("${svg.certificate.template}") + private String svgCertificateTemplate; /** * Método que apresenta a tela inicial do cliente * @return @@ -273,7 +309,7 @@ public ModelAndView showDetailsRequestCandidate(@PathVariable Optional job public ModelAndView showAvailableJobs( HttpServletRequest request, @RequestParam(value = "pag", defaultValue = "1") int page, - @RequestParam(value = "siz", defaultValue = "3") int size, + @RequestParam(value = "siz", defaultValue = "4") int size, @RequestParam(value = "ord", defaultValue = "id") String order, @RequestParam(value = "dir", defaultValue = "ASC") String direction ) throws Exception { @@ -764,16 +800,191 @@ public String markAsHided(@PathVariable Long jobId, @PathVariable Long userId, R jobRequest.setStatus(JobRequest.Status.TO_HIRED); jobRequestService.save(jobRequest); + System.out.println("JOBBBBBBBBB" + oJobRequest.get()); + //guarda a data de contratação - Optional oJobContracted = jobContractedService.findByJobRequest(jobRequest); - if(!oJobContracted.isPresent()) { - throw new EntityNotFoundException("O profissional não pode ser contratado!"); - } + Optional oJobContracted = jobContractedService.findByJobRequest(oJobRequest.get()); +// if(!oJobContracted.isPresent()) { +// throw new EntityNotFoundException("O profissional não pode ser contratado!"); +// } + Optional oUser = userService.findById(userId); - JobContracted jobContracted = oJobContracted.get(); + JobContracted jobContracted = new JobContracted(); jobContracted.setHiredDate(LocalDate.now()); + jobContracted.setJobRequest(oJobRequest.get()); + jobContracted.setUser(oUser.get()); jobContractedService.save(jobContracted); return "redirect:/minha-conta/cliente/meus-pedidos/"+jobId; } + + /** + * Responsável por realizar o pagamento via API Mercado Pago. + */ + @PostMapping("/pagamento") + @RolesAllowed({RoleType.USER}) + public ResponseEntity createPayment(@RequestBody Map paymentData){ + ResponseDTO response = new ResponseDTO(); + + try { + if (paymentData == null || paymentData.isEmpty()) { + response.setMessage("Erro ao enviar dados. Verifique os campos e tente novamente!"); + return ResponseEntity.status(400).body(response); + } + + Optional oUser = (userService.findByEmail(authentication.getEmail())); + + if (!oUser.isPresent()) { + response.setMessage("Usuário não autenticado! Por favor, realize sua autenticação no sistema."); + return ResponseEntity.status(401).body(response); + } + + ResponseEntity paymentResponse = paymentService.pay(paymentData); + + if(!paymentResponse.getStatusCode().is2xxSuccessful()){ + response.setMessage("Erro ao processar pagamento. Tente novamente"); + return ResponseEntity.status(paymentResponse.getStatusCode()).body(response); + } + + Object responseBody = paymentResponse.getBody(); + + Map responseMap = (Map) responseBody; + Integer paymentId = (Integer) responseMap.get("id"); + String status = (String) responseMap.get("status"); + + PaymentDTO paymentDTO = new PaymentDTO(paymentId, status); + Payment payment = paymentMapper.toEntity(paymentDTO); + + paymentService.save(payment); + + response.setData(paymentResponse.getBody()); + + + + System.out.println("SATTSUS PAGAMENTO....."); + System.out.println(status); + + + return ResponseEntity.ok(response); + + + } catch (Exception e) { + response.setMessage("Erro ao fazer pagamento. Por favor, tente novamente."); + return ResponseEntity.status(400).body(response); + } + } + + /** + * Apos processar o pagamento, ele é inserido na tabela payments_jobRequests + * contendo o id do pagamento e do serviço que foi realizado o pagamento. + * Finalizado este processo é preciso gerar um comprovante do pagamento + * tanto para cliente quanto profissional, que sera enviado por email + * **/ + @PostMapping("/pagamento/jobRequest") + @RolesAllowed({RoleType.USER}) + public ModelAndView savePaymentJob(@RequestBody PaymentJobDTO dto, BindingResult errors, RedirectAttributes redirectAttributes) throws ConfigurationException, TranscoderException, IOException, TransformerException, WriterException { + ModelAndView modelAndView = new ModelAndView(); + final Date now = new Date(); + + Optional oPayment = paymentService.find(dto.getPaymentId()); + Optional oJobRequest = jobRequestService.findById(dto.getJobRequestId()); + + PaymentJobRequest paymentJob = new PaymentJobRequest(); + paymentJob.setJobRequestId(dto.getJobRequestId()); + paymentJob.setPayment(oPayment.get()); + paymentJob.setJobRequest(oJobRequest.get()); + paymentJob.setDateCreated(now); + + paymentJobService.save(paymentJob); + + createVoucherPayment(paymentJob); // GERA O COMPROVANTE DE PAGAMENTO + + modelAndView.addObject("mensagem", "Pagamento processado com sucesso!"); + + return modelAndView; + } + + public String createVoucherPayment(PaymentJobRequest paymentJob) throws IOException, TranscoderException, ConfigurationException, TransformerException, WriterException, TransformerException { + /*Busca o job request - cliente*/ + Optional oJobRequest = jobRequestService.findById(paymentJob.getJobRequestId()); + + /*Traz o profissional*/ + Optional oJobContracted = jobContractedService.findByJobRequest(oJobRequest.get()); + + /*Traz o servico*/ + Optional oExpertise = expertiseService.findById(oJobRequest.get().getExpertise().getId()); + + PaymentVoucher paymentVoucher = new PaymentVoucher(); + paymentVoucher.setClient(oJobRequest.get().getUser()); + paymentVoucher.setProfessional(oJobContracted.get().getUser()); + paymentVoucher.setCode(gerarCodigoAlfanumerico()); + paymentVoucher.setJobRequest(oJobRequest.get()); + + String emailProfissional = oJobContracted.get().getUser().getEmail(); + String emailClient = oJobRequest.get().getUser().getEmail(); + + paymentVoucherService.save(paymentVoucher); + Date dataAtual = new Date(); + + // Converter LocalDate para Date + SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy"); + + Calendar calendar = Calendar.getInstance(); + calendar.setTime(dataAtual); + + // Incrementando 15 dias + calendar.add(Calendar.DATE, 15); + + // Obtendo a nova data após o incremento + Date dataFinal = calendar.getTime(); + SimpleDateFormat sdfNovo = new SimpleDateFormat("dd/MM/yyyy"); + + String client_name = paymentVoucher.getClient().getName(); // NOME DO CLIENTE + String client_fone = paymentVoucher.getClient().getPhoneNumber(); // TELEFONE DO CLIENTE + String client_email = paymentVoucher.getClient().getEmail(); // EMAIL DO CLIENTE + String client_address_name = paymentVoucher.getClient().getAddress().getNeighborhood(); // ENDEREÇO DO CLIENTE + String client_address_number = paymentVoucher.getClient().getAddress().getNumber(); // NUMERO ENDEREÇO DO CLIENTE + String client_address = client_address_name + " - " + client_address_number; // ENDEREÇO DO CLIENTE + + String profes_name = paymentVoucher.getProfessional().getName(); // NOME DO PROFISSIONAL + String profes_fone = paymentVoucher.getProfessional().getPhoneNumber(); // TELEFONE DO PROFISSIONAL + String profes_email = paymentVoucher.getProfessional().getEmail(); // EMAIL DO PROFISSIONAL + String profes_address_name = paymentVoucher.getProfessional().getAddress().getNeighborhood(); // ENDEREÇO DO PROFISSIONAL + String profes_address_number = paymentVoucher.getProfessional().getAddress().getNumber(); // NUMERO ENDEREÇO DO PROFISSIONAL + String profes_address = profes_address_name + " - " + profes_address_number; // ENDEREÇO DO PROFISSIONAL + + String service_name = oJobRequest.get().getExpertise().getName(); + + Optional optionalProfessionalServiceOffering = professionalServiceOfferingService.findProfessionalServiceOfferingByExpertiseAAndUser(paymentVoucher.getProfessional().getId(), oJobRequest.get().getExpertise().getId()); + + String value_service = "0,00"; + if (optionalProfessionalServiceOffering.isPresent()){ + value_service = String.valueOf(optionalProfessionalServiceOffering.get().getPrice()); + } + + File pdfFile = paymentVoucherService.generateCertificate(svgCertificateTemplate, paymentVoucher.getCode(),service_name, sdfNovo.format(dataAtual), sdfNovo.format(dataFinal), + client_name, "111111111", client_fone, client_email, profes_name, "10444444440", + profes_email, profes_fone, profes_address, "PIX", value_service, "QRDCOD"); + Map uploadResult = cloudinary.uploader().upload(pdfFile, ObjectUtils.asMap("folder", "certificates")); + + String uploadURL = (String)uploadResult.get("url"); + + //envia um email com a URL do certificado + /*Envio de email para o profissional*/ + quartzService.sendEmailPaymentVoucher(paymentVoucher.getCode(), + oJobRequest.get().getUser().getId(), oJobContracted.get().getUser().getId(), oExpertise.get().getName(), sdf.format(dataFinal), (String)uploadResult.get("url")); + pdfFile.delete(); + +// (url.openStream(), voucher, service,date, date_due,name_client,document_client,fone_client,mail_client,name_professional, document_professional, +// mail_professional, fone_professional, endereco_pro, payment_type, payment_value, qrCode); + + return "redirect:/minha-conta/cliente#executados"; + } + + /* Gera código aleatorico e unico para gravação de comprovante */ + private String gerarCodigoAlfanumerico() { + UUID uuid = UUID.randomUUID(); + String codigo = uuid.toString().replace("-", "").substring(0, 10); + return codigo.toUpperCase(); + } } \ No newline at end of file diff --git a/src/main/java/br/edu/utfpr/servicebook/controller/IndexController.java b/src/main/java/br/edu/utfpr/servicebook/controller/IndexController.java index e1c2b3bd..49b3bd06 100644 --- a/src/main/java/br/edu/utfpr/servicebook/controller/IndexController.java +++ b/src/main/java/br/edu/utfpr/servicebook/controller/IndexController.java @@ -1,7 +1,13 @@ package br.edu.utfpr.servicebook.controller; +import br.edu.utfpr.servicebook.model.dto.CategoryDTO; +import br.edu.utfpr.servicebook.model.dto.ExpertiseDTO; import br.edu.utfpr.servicebook.model.dto.JobRequestFullDTO; +import br.edu.utfpr.servicebook.model.dto.ServiceDTO; import br.edu.utfpr.servicebook.model.entity.*; +import br.edu.utfpr.servicebook.model.mapper.CategoryMapper; +import br.edu.utfpr.servicebook.model.mapper.ExpertiseMapper; +import br.edu.utfpr.servicebook.model.mapper.ServiceMapper; import br.edu.utfpr.servicebook.security.IAuthentication; import br.edu.utfpr.servicebook.security.RoleType; import br.edu.utfpr.servicebook.service.*; @@ -15,20 +21,20 @@ import org.springframework.data.domain.Page; import org.springframework.security.authentication.AnonymousAuthenticationToken; import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.*; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.mvc.support.RedirectAttributes; import javax.annotation.security.PermitAll; import javax.annotation.security.RolesAllowed; +import javax.persistence.EntityNotFoundException; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import java.util.List; import java.util.Optional; +import java.util.stream.Collectors; @RequestMapping("/") @Controller @@ -61,6 +67,20 @@ public class IndexController { @Autowired private HttpSession httpSession; + @Autowired + private CategoryService categoryService; + + @Autowired + private CategoryMapper categoryMapper; + + @Autowired + private ExpertiseMapper expertiseMapper; + + @Autowired + private ServiceService serviceService; + + @Autowired + private ServiceMapper serviceMapper; @GetMapping @PermitAll public ModelAndView showIndexPage(HttpServletResponse response) { @@ -81,6 +101,11 @@ public ModelAndView showIndexPage(HttpServletResponse response) { return new ModelAndView("redirect:/minha-conta/empresa/disponiveis"); } } + //lista de categorias + List categories = categoryService.findAll(); + List categoryDTOs = categories.stream() + .map(s -> categoryMapper.toDto(s)) + .collect(Collectors.toList()); List cities = cityService.findAll(); mv.addObject("cities", cities); @@ -90,6 +115,7 @@ public ModelAndView showIndexPage(HttpServletResponse response) { mv.addObject("totalJobContracted", jobContractedService.countAll()); mv.addObject("totalProfessionals", userService.countProfessionals()); mv.addObject("totalClients", userService.countUsersWithoutExpertise()); + mv.addObject("categories", categoryDTOs); return mv; } @@ -101,8 +127,6 @@ public String showClientPage(HttpSession httpSession, RedirectAttributes redirec return "redirect:/"; } - - @GetMapping("/bem-vindo") @PermitAll public ModelAndView showWelcomePage() { @@ -122,4 +146,53 @@ public String notAuthorized() { return "error/not-authorized"; } + @GetMapping("/especialidades/categoria/{categoryId}") + @PermitAll + @ResponseBody + public List showExpertisesByCategory(@PathVariable Long categoryId) throws Exception { + if(categoryId != null){ + List expertises = expertiseService.findByCategoryId(categoryId); + + List expertiseDTOS = expertises.stream() + .map(s -> expertiseMapper.toDto(s)) + .collect(Collectors.toList()); + + return expertiseDTOS; + } else { + List expertises = expertiseService.findAll(); + + List expertiseDTOS = expertises.stream() + .map(s -> expertiseMapper.toDto(s)) + .collect(Collectors.toList()); + + return expertiseDTOS; + } + + } + + @GetMapping("/servicos/especialidade/{expertiseId}") + @PermitAll + @ResponseBody + public List showServicesByExpertise(@PathVariable Long expertiseId) throws Exception { + if(expertiseId != null){ + Expertise expertise = expertiseService.findById(expertiseId).orElseThrow(() -> new EntityNotFoundException("Especialidade não encontrada")); + + List services = serviceService.findByExpertise(expertise); + + List servicesDTO = services.stream() + .map(s -> serviceMapper.toDto(s)) + .collect(Collectors.toList()); + return servicesDTO; + + } else { + List services = serviceService.findAll(); + + List servicesDTO = services.stream() + .map(s -> serviceMapper.toDto(s)) + .collect(Collectors.toList()); + + return servicesDTO; + } + + } } \ No newline at end of file diff --git a/src/main/java/br/edu/utfpr/servicebook/controller/JobContractedController.java b/src/main/java/br/edu/utfpr/servicebook/controller/JobContractedController.java index 4ff0414e..021be80a 100644 --- a/src/main/java/br/edu/utfpr/servicebook/controller/JobContractedController.java +++ b/src/main/java/br/edu/utfpr/servicebook/controller/JobContractedController.java @@ -104,13 +104,13 @@ public String markAsToDo( JobContracted jobContracted = oJobContracted.get(); if (dto.isConfirm()) { - DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("dd/MM/yyyy"); JobRequest jobRequest = jobContracted.getJobRequest(); jobRequest.setStatus(JobRequest.Status.TO_DO); jobRequestService.save(jobRequest); - jobContracted.setTodoDate(LocalDate.parse(dto.getTodoDate(), dateTimeFormatter)); +// jobContracted.setTodoDate(LocalDate.parse(dto.getTodoDate(), dateTimeFormatter)); + jobContracted.setTodoDate(LocalDate.parse(dto.getTodoDate())); jobContractedService.save(jobContracted); } else { JobRequest jobRequest = jobContracted.getJobRequest(); diff --git a/src/main/java/br/edu/utfpr/servicebook/controller/JobRequestController.java b/src/main/java/br/edu/utfpr/servicebook/controller/JobRequestController.java index 00f8f6b7..3f7fd2e2 100644 --- a/src/main/java/br/edu/utfpr/servicebook/controller/JobRequestController.java +++ b/src/main/java/br/edu/utfpr/servicebook/controller/JobRequestController.java @@ -22,6 +22,7 @@ import com.cloudinary.utils.ObjectUtils; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.validation.BindingResult; @@ -121,6 +122,14 @@ public String showWizard(@RequestParam(value = "passo", required = false, defaul if(step < 1 || step > 8){ step = 1L; } + + String currentUserEmail = authentication.getEmail(); + + Optional oUser = userService.findByEmail(currentUserEmail); +// if (!oUser.isPresent()) { +// return "redirect:/login"; +// } + JobRequestDTO dto = wizardSessionUtil.getWizardState(httpSession, JobRequestDTO.class, WizardSessionUtil.KEY_WIZARD_JOB_REQUEST); model.addAttribute("dto", dto); @@ -291,7 +300,7 @@ public String saveFormImagePath(HttpSession httpSession, RedirectAttributes redi sessionDTO.setImageSession((String)data.get("url")); log.debug("Passo 5 {}", sessionDTO); - return "redirect:/requisicoes/passo=5"; + return "redirect:/requisicoes?passo=8"; } else { return "redirect:/requisicoes/passo=5"; } @@ -336,7 +345,7 @@ public String saveFormVerification(HttpSession httpSession, JobRequestDTO dto, R User user = null; Optional oUser = userService.findByEmail(authentication.getEmail()); if(oUser.isPresent()){ - user = oUser.get(); + user = oUser.get(); } Expertise exp = oExpertise.get(); @@ -456,4 +465,4 @@ public String rememberToHide(@PathVariable Long id, RedirectAttributes redirectA return "redirect:/minha-conta/profissional#disponiveis"; } -} +} \ No newline at end of file diff --git a/src/main/java/br/edu/utfpr/servicebook/controller/MyAdsController.java b/src/main/java/br/edu/utfpr/servicebook/controller/MyAdsController.java new file mode 100644 index 00000000..dd96f204 --- /dev/null +++ b/src/main/java/br/edu/utfpr/servicebook/controller/MyAdsController.java @@ -0,0 +1,324 @@ +package br.edu.utfpr.servicebook.controller; + +import br.edu.utfpr.servicebook.model.dto.*; +import br.edu.utfpr.servicebook.model.entity.*; +import br.edu.utfpr.servicebook.model.mapper.ExpertiseMapper; +import br.edu.utfpr.servicebook.model.mapper.ServiceMapper; +import br.edu.utfpr.servicebook.security.IAuthentication; +import br.edu.utfpr.servicebook.security.RoleType; +import br.edu.utfpr.servicebook.service.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.stereotype.Controller; +import org.springframework.validation.BindingResult; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.servlet.ModelAndView; +import org.springframework.web.servlet.mvc.support.RedirectAttributes; +import javax.annotation.security.PermitAll; +import javax.annotation.security.RolesAllowed; +import javax.persistence.EntityNotFoundException; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; +@RequestMapping("/minha-conta/profissional/meus-anuncios") +@Controller +public class MyAdsController { + public static final Logger log = LoggerFactory.getLogger(ProfessionalHomeController.class); + + @Autowired + private ServiceService serviceService; + + @Autowired + private ServiceMapper serviceMapper; + + @Autowired + private ExpertiseService expertiseService; + + @Autowired + private ExpertiseMapper expertiseMapper; + + @Autowired + private ProfessionalServiceOfferingService professionalServiceOfferingService; + + @Autowired + private UserService userService; + + @Autowired + private IAuthentication authentication; + + @Autowired + private ProfessionalServicePackageOfferingService professionalServicePackageOfferingService; + + @Autowired + private ProfessionalServiceOfferingAdItemService professionalServiceOfferingAdItemService; + + @GetMapping + @PermitAll + protected ModelAndView showMyAds() throws Exception { + ModelAndView mv = new ModelAndView("professional/my-ads"); + Optional oUser = (userService.findByEmail(authentication.getEmail())); + + //paginação de serviços + PageRequest pageRequest = PageRequest.of(0, 5); + Page servicePage = serviceService.findAll(pageRequest); + + Page expertisePage = expertiseService.findAll(pageRequest); + + List expertiseDTOS = expertisePage.stream() + .map(s -> expertiseMapper.toDto(s)) + .collect(Collectors.toList()); + + List serviceDTOS = servicePage.stream() + .map(s -> serviceMapper.toDto(s)) + .collect(Collectors.toList()); + + List professionalServiceOfferings = professionalServiceOfferingService.findProfessionalServiceOfferingByUser(oUser.get()); + List servicesIndividuals = professionalServiceOfferingService.findFirst3ProfessionalServiceOfferingByUserAndType(oUser.get(), ProfessionalServiceOffering.Type.INDIVIDUAL); + + List servicesPackages = professionalServicePackageOfferingService.findAllByUserAndType(oUser.get(), ProfessionalServicePackageOffering.Type.SIMPLE_PACKAGE); + List servicesCombined = professionalServicePackageOfferingService.findByTypeAndUser(oUser.get(), ProfessionalServicePackageOffering.Type.COMBINED_PACKAGE); + List teste = professionalServiceOfferingAdItemService.findAllByProfessionalServicePackageOfferingUser(oUser.get()); + + mv.addObject("expertises", expertiseDTOS); + mv.addObject("professionalServiceOfferings", professionalServiceOfferings); + mv.addObject("servicesIndividuals", servicesIndividuals); + mv.addObject("servicesPackages", servicesPackages); + mv.addObject("servicesCombined", servicesCombined); + mv.addObject("teste", teste); + return mv; + } + + @GetMapping("/novo") + @PermitAll + protected ModelAndView registerMyAds() throws Exception { + ModelAndView mv = new ModelAndView("professional/my-ads-register"); + + //paginação de serviços + PageRequest pageRequest = PageRequest.of(0, 5); + + List expertises = expertiseService.findAll(); + List expertiseDTOs = expertises.stream() + .map(s -> expertiseMapper.toDto(s)) + .collect(Collectors.toList()); + mv.addObject("expertises", expertiseDTOs); + + Page servicePage = serviceService.findAll(pageRequest); + List serviceDTOS = servicePage.stream() + .map(s -> serviceMapper.toDto(s)) + .collect(Collectors.toList()); +// mv.addObject("services", serviceDTOS); + return mv; + } + + /** + * Adiciona um serviço individual. + * @param professionalServiceOfferingDTO + * @param errors + * @param redirectAttributes + * @return + * @throws Exception + */ + @PostMapping("/novo/individual") + @PermitAll + public String saveAds(ProfessionalServiceOfferingDTO professionalServiceOfferingDTO, BindingResult errors, RedirectAttributes + redirectAttributes) throws Exception { + Optional oUser = (userService.findByEmail(authentication.getEmail())); + + ModelAndView mv = new ModelAndView("professional/my-ads-register"); + + ProfessionalServiceOffering professionalServiceOffering = new ProfessionalServiceOffering(); + Optional oService = serviceService.findById(professionalServiceOfferingDTO.getServiceId()); + professionalServiceOffering.setUser(oUser.get()); + professionalServiceOffering.setPrice(professionalServiceOfferingDTO.getPrice()); + professionalServiceOffering.setUnit(professionalServiceOfferingDTO.getUnit()); + professionalServiceOffering.setDuration(professionalServiceOfferingDTO.getDuration()); + professionalServiceOffering.setType(ProfessionalServiceOffering.Type.INDIVIDUAL); + + professionalServiceOffering.setDescription(professionalServiceOfferingDTO.getDescription()); + if(oService.isPresent()){ + professionalServiceOffering.setService(oService.get()); + } + + //grava o nome do serviço original + professionalServiceOffering.setName(oService.get().getName()); + professionalServiceOfferingService.save(professionalServiceOffering); + + return("redirect:/minha-conta/profissional/meus-anuncios"); + } + + /** + * Adiciona um pacote de serviço. + * @param professionalServicePackageOfferingDTO + * @param professionalServiceOfferingDTO + * @return + * @throws Exception + */ + @PostMapping("/novo/pacote") + @PermitAll + public String saveAdsPackage(ProfessionalServiceOfferingDTO professionalServiceOfferingDTO, ProfessionalServicePackageOfferingDTO professionalServicePackageOfferingDTO, BindingResult errors, RedirectAttributes + redirectAttributes) throws Exception { + Optional oUser = (userService.findByEmail(authentication.getEmail())); + ModelAndView mv = new ModelAndView("professional/my-ads-register"); + + Optional oService = serviceService.findById(professionalServicePackageOfferingDTO.getServiceId()); + + ProfessionalServicePackageOffering professionalServicePackageOffering = new ProfessionalServicePackageOffering(); + professionalServicePackageOffering.setPrice(professionalServicePackageOfferingDTO.getPrice()); + professionalServicePackageOffering.setType(ProfessionalServicePackageOffering.Type.SIMPLE_PACKAGE); + professionalServicePackageOffering.setUnit(professionalServicePackageOfferingDTO.getUnit()); + professionalServicePackageOffering.setDuration(professionalServicePackageOfferingDTO.getDuration()); + professionalServicePackageOffering.setDescription(professionalServicePackageOfferingDTO.getDescription()); + //grava o nome do serviço original + professionalServicePackageOffering.setName(oService.get().getName()); + professionalServicePackageOffering.setAmount(professionalServicePackageOfferingDTO.getAmount()); + professionalServicePackageOffering.setUser(oUser.get()); + professionalServicePackageOffering.setService(oService.get()); + + professionalServicePackageOfferingService.save(professionalServicePackageOffering); + + return("redirect:/minha-conta/profissional/meus-anuncios"); + } + /** + * Adiciona um serviço combinado com um ou mais serviços. + * @param professionalServicePackageOfferingDTO + * @param professionalServiceOfferingDTO + * @return + * @throws Exception + */ + @PostMapping("/novo/combinado") + @PermitAll + public String saveAdsCombined(ProfessionalServiceOfferingDTO professionalServiceOfferingDTO, ProfessionalServicePackageOfferingDTO professionalServicePackageOfferingDTO, BindingResult errors, RedirectAttributes + redirectAttributes) throws Exception { + Optional oUser = (userService.findByEmail(authentication.getEmail())); + Optional oExpertise = expertiseService.findById(professionalServicePackageOfferingDTO.getExpertiseId()); + + ModelAndView mv = new ModelAndView("professional/my-ads-register"); + ProfessionalServicePackageOffering professionalServicePackageOffering = new ProfessionalServicePackageOffering(); + professionalServicePackageOffering.setPrice(professionalServicePackageOfferingDTO.getPrice()); + professionalServicePackageOffering.setType(ProfessionalServicePackageOffering.Type.COMBINED_PACKAGE); + professionalServicePackageOffering.setUnit(professionalServicePackageOfferingDTO.getUnit()); + professionalServicePackageOffering.setDuration(professionalServicePackageOfferingDTO.getDuration()); + professionalServicePackageOffering.setDescription(professionalServicePackageOfferingDTO.getDescription()); + professionalServicePackageOffering.setName(professionalServicePackageOfferingDTO.getDescription()); + professionalServicePackageOffering.setExpertise(oExpertise.get()); + professionalServicePackageOffering.setName(professionalServicePackageOfferingDTO.getDescription()); + + //grava o nome do serviço original + professionalServicePackageOffering.setUser(oUser.get()); + + professionalServicePackageOfferingService.save(professionalServicePackageOffering); + + for (Long valor : professionalServiceOfferingDTO.getDescriptions()) { + ProfessionalServiceOffering professionalServiceOffering = new ProfessionalServiceOffering(); + Optional oService = serviceService.findById(valor); + + professionalServiceOffering.setDescription(professionalServicePackageOfferingDTO.getDescription()); + //grava o nome do serviço original + professionalServiceOffering.setName(oService.get().getName()); + professionalServiceOffering.setType(ProfessionalServiceOffering.Type.COMBINED_PACKAGE); + professionalServiceOffering.setUnit(professionalServiceOfferingDTO.getUnit()); + professionalServiceOffering.setDuration(professionalServiceOfferingDTO.getDuration()); + professionalServiceOffering.setPrice(professionalServiceOfferingDTO.getPrice()); + professionalServiceOffering.setUser(oUser.get()); + professionalServiceOffering.setService(oService.get()); + professionalServiceOfferingService.save(professionalServiceOffering); +// + ProfessionalServiceOfferingAdItem professionalServiceOfferingAdItem = new ProfessionalServiceOfferingAdItem(professionalServiceOffering, professionalServicePackageOffering); + professionalServiceOfferingAdItemService.save(professionalServiceOfferingAdItem); + + } + + return("redirect:/minha-conta/profissional/meus-anuncios"); + } + @GetMapping("/pacotes") + @PermitAll + protected ModelAndView showMyAdsPackages() throws Exception { + ModelAndView mv = new ModelAndView("professional/ads/my-ads-packages"); + Optional oUser = (userService.findByEmail(authentication.getEmail())); + + //paginação de serviços + PageRequest pageRequest = PageRequest.of(0, 5); + Page servicePage = serviceService.findAll(pageRequest); + List serviceDTOS = servicePage.stream() + .map(s -> serviceMapper.toDto(s)) + .collect(Collectors.toList()); + + List servicesPackages = professionalServicePackageOfferingService.findByTypeAndUser(oUser.get(), ProfessionalServicePackageOffering.Type.SIMPLE_PACKAGE); + + mv.addObject("services", serviceDTOS); + mv.addObject("servicesPackages", servicesPackages); + return mv; + } + + @GetMapping("/individuais") + @PermitAll + protected ModelAndView showMyAdsIndividuals() throws Exception { + ModelAndView mv = new ModelAndView("professional/ads/my-ads-individuals"); + Optional oUser = (userService.findByEmail(authentication.getEmail())); + + //paginação de serviços + PageRequest pageRequest = PageRequest.of(0, 5); + Page servicePage = serviceService.findAll(pageRequest); + List serviceDTOS = servicePage.stream() + .map(s -> serviceMapper.toDto(s)) + .collect(Collectors.toList()); + + List professionalServiceOfferings = professionalServiceOfferingService.findProfessionalServiceOfferingByUserAndType(oUser.get(), ProfessionalServiceOffering.Type.INDIVIDUAL); + + mv.addObject("services", serviceDTOS); + mv.addObject("professionalServiceOfferings", professionalServiceOfferings); + return mv; + } + + @GetMapping("/combinados") + @PermitAll + protected ModelAndView showMyAdsCombineds() throws Exception { + ModelAndView mv = new ModelAndView("professional/ads/my-ads-combineds"); + Optional oUser = (userService.findByEmail(authentication.getEmail())); + + //paginação de serviços + PageRequest pageRequest = PageRequest.of(0, 5); + Page servicePage = serviceService.findAll(pageRequest); + List serviceDTOS = servicePage.stream() + .map(s -> serviceMapper.toDto(s)) + .collect(Collectors.toList()); + + List servicesCombined = professionalServicePackageOfferingService.findByTypeAndUser(oUser.get(), ProfessionalServicePackageOffering.Type.COMBINED_PACKAGE); + + mv.addObject("services", serviceDTOS); + mv.addObject("servicesCombined", servicesCombined); + return mv; + } + @GetMapping("/especialidade/{expertiseId}") + @RolesAllowed({RoleType.USER, RoleType.COMPANY}) + @ResponseBody + public List findAdsByExpertise(@PathVariable Long expertiseId) throws Exception { + + User professional = this.getAuthenticatedUser(); + + Expertise expertise = expertiseService.findById(expertiseId).orElseThrow(() -> new EntityNotFoundException("Especialidade não encontrada")); + + //lista de serviços + List services = serviceService.findByExpertise(expertise); + List professionalServiceOfferings = professionalServiceOfferingService.findProfessionalServiceOfferingByUserAndExpertise(professional.getId(), expertiseId); + + return professionalServiceOfferings; + } + /** + * Retorna o indivíduo logado. + * @return + * @throws Exception + */ + private User getAuthenticatedUser() throws Exception { + Optional oProfessional = (userService.findByEmail(authentication.getEmail())); + + if (!oProfessional.isPresent()) { + throw new EntityNotFoundException("Usuário não autenticado! Por favor, realize sua autenticação no sistema."); + } + + return oProfessional.get(); + } +} \ No newline at end of file diff --git a/src/main/java/br/edu/utfpr/servicebook/controller/ProfessionalController.java b/src/main/java/br/edu/utfpr/servicebook/controller/ProfessionalController.java index e64b516c..72c48a9f 100644 --- a/src/main/java/br/edu/utfpr/servicebook/controller/ProfessionalController.java +++ b/src/main/java/br/edu/utfpr/servicebook/controller/ProfessionalController.java @@ -2,10 +2,7 @@ import br.edu.utfpr.servicebook.model.dto.*; import br.edu.utfpr.servicebook.model.entity.*; -import br.edu.utfpr.servicebook.model.mapper.IndividualMapper; -import br.edu.utfpr.servicebook.model.mapper.JobContractedMapper; -import br.edu.utfpr.servicebook.model.mapper.ProfessionalServiceOfferingMapper; -import br.edu.utfpr.servicebook.model.mapper.UserMapper; +import br.edu.utfpr.servicebook.model.mapper.*; import br.edu.utfpr.servicebook.security.IAuthentication; import br.edu.utfpr.servicebook.service.*; @@ -15,8 +12,10 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.data.domain.Page; import org.springframework.stereotype.Controller; +import org.springframework.validation.BindingResult; import org.springframework.web.bind.annotation.*; import org.springframework.web.servlet.ModelAndView; +import org.springframework.web.servlet.mvc.support.RedirectAttributes; import javax.annotation.security.PermitAll; import javax.persistence.EntityNotFoundException; @@ -73,6 +72,18 @@ public class ProfessionalController { @Autowired private PaginationUtil paginationUtil; + @Autowired + private ServiceService serviceService; + + @Autowired + private ExpertiseService expertiseService; + + @Autowired + private CategoryService categoryService; + + @Autowired + private CategoryMapper categoryMapper; + @GetMapping @PermitAll protected ModelAndView showAll() throws Exception { @@ -106,7 +117,8 @@ protected ModelAndView showAll() throws Exception { * Retorna a lista de profissionais de acordo com o termo de busca. * Se estiver logado, o usuário poderá ter acesso a todos os profissionais de acordo com a sua busca. * Caso seja um visitante, terá acesso a apenas 4 profissionais. - * @param searchTerm + * + * @param searchService * @param page * @return * @throws Exception @@ -114,8 +126,12 @@ protected ModelAndView showAll() throws Exception { @GetMapping(value = "/busca") @PermitAll protected ModelAndView showSearchResults( - @RequestParam(value = "termo-da-busca") String searchTerm, - @RequestParam(value = "pag", defaultValue = "1") int page +// @RequestParam(value = "termo-da-busca") String searchTerm, + @RequestParam(defaultValue = "0", value = "serviceId") Long searchService, + @RequestParam(defaultValue = "", value = "expertiseId") Long searchExpertise, + @RequestParam(defaultValue = "", value = "categoryId") Long searchCategory, + @RequestParam(value = "pag", defaultValue = "1") int page, + RedirectAttributes redirectAttributes ) throws Exception { ModelAndView mv = new ModelAndView("visitor/search-results"); @@ -132,17 +148,50 @@ protected ModelAndView showSearchResults( page = 1; size = this.paginationSizeVisitor; } + if (searchService == 0) { + redirectAttributes.addFlashAttribute("msg", "A atualização foi salva com sucesso!"); + } else { - Page professionals = individualService.findDistinctByTermIgnoreCaseWithPagination(searchTerm, page, size); - List professionalSearchItemDTOS = professionals.stream() - .map(s -> individualMapper.toSearchItemDto(s, individualService.getExpertises(s))) - .collect(Collectors.toList()); + Optional service = serviceService.findById(searchService); + Optional expertise = expertiseService.findById(searchExpertise); + Optional category = categoryService.findById(searchCategory); + + Page professionals = individualService.findAllIndividualsByService(service.get(), page, size); + Page professionalServiceOfferings = professionalServiceOfferingService.findAllIndividualsByService(service.get(), page, size); - PaginationDTO paginationDTO = paginationUtil.getPaginationDTO(professionals, "/profissionais/busca?termo-da-busca="+ searchTerm); - mv.addObject("professionals", professionalSearchItemDTOS); - mv.addObject("pagination", paginationDTO); - mv.addObject("isParam", true); - mv.addObject("searchTerm", searchTerm); + List professionalSearchItemDTOS = professionals.stream() + .map(s -> individualMapper.toSearchItemDto(s, individualService.getExpertises(s))) + .collect(Collectors.toList()); + + List professionalServiceOfferingDTOS = professionalServiceOfferings.stream() + .map(s -> professionalServiceOfferingMapper.toDTO(s)).collect(Collectors.toList()); + + //lista de categorias + List categories = categoryService.findAll(); + List categoryDTOs = categories.stream() + .map(s -> categoryMapper.toDto(s)) + .collect(Collectors.toList()); + + PaginationDTO paginationDTO = paginationUtil.getPaginationDTO(professionals, "/profissionais/busca?termo-da-busca=" + searchService); + + + List professionals1 = individualService.findAllIndividualsAutonomosByService(expertise.get().getId(), page, size); + List professionalSearchItemDTOS1 = professionals1.stream() + .map(s -> individualMapper.toSearchItemDto(s, individualService.getExpertises(s))) + .collect(Collectors.toList()); + + mv.addObject("professionals", professionals1); + mv.addObject("categoryDTOs", categoryDTOs); + mv.addObject("pagination", paginationDTO); + mv.addObject("isParam", true); + mv.addObject("service", service.get().getName()); + mv.addObject("searchTerm", searchService); + mv.addObject("dto_expertise", expertise.get()); + mv.addObject("dto", category.get()); + mv.addObject("dto_service", service.get()); + + mv.addObject("professionalServiceOfferingDTOS", professionalServiceOfferingDTOS); + } return mv; } @@ -150,6 +199,7 @@ protected ModelAndView showSearchResults( /** * Retorna a página de detalhes do profissional. * Esta página pode ser acessada de forma autenticada ou anônima. + * * @param id * @return * @throws Exception @@ -160,7 +210,7 @@ protected ModelAndView showProfessionalDetailsToVisitors(@PathVariable("id") Lon Optional oProfessional = userService.findById(id); - if(!oProfessional.isPresent()) { + if (!oProfessional.isPresent()) { throw new EntityNotFoundException("Profissional não encontrado."); } @@ -177,10 +227,10 @@ protected ModelAndView showProfessionalDetailsToVisitors(@PathVariable("id") Lon //serviços por especialidade Map> servicesByExpertise = new HashMap<>(); - for(ProfessionalExpertise pe : professionalExpertises) { + for (ProfessionalExpertise pe : professionalExpertises) { List professionalServiceOfferings = professionalServiceOfferingService.findProfessionalServiceOfferingByUserAndExpertise(oProfessional.get().getId(), pe.getExpertise().getId()); - if(professionalServiceOfferings.isEmpty()){ + if (professionalServiceOfferings.isEmpty()) { continue; } @@ -199,7 +249,7 @@ protected ModelAndView showProfessionalDetailsToVisitors(@PathVariable("id") Lon mv.addObject("servicesByExpertise", servicesByExpertise); //se o cliente está logado, mostra se ele segue o profissional - if(oClientAuthenticated.isPresent()){ + if (oClientAuthenticated.isPresent()) { List follows = followsService.findFollowProfessionalClient(oProfessional.get(), oClientAuthenticated.get()); boolean isFollow = !follows.isEmpty(); UserDTO clientDTO = userMapper.toDto(oClientAuthenticated.get()); diff --git a/src/main/java/br/edu/utfpr/servicebook/jobs/SendEmailVoucher.java b/src/main/java/br/edu/utfpr/servicebook/jobs/SendEmailVoucher.java new file mode 100644 index 00000000..61c20ff0 --- /dev/null +++ b/src/main/java/br/edu/utfpr/servicebook/jobs/SendEmailVoucher.java @@ -0,0 +1,136 @@ +package br.edu.utfpr.servicebook.jobs; + +import br.edu.utfpr.servicebook.service.EmailSenderService; +import br.edu.utfpr.servicebook.service.UserService; +import com.itextpdf.layout.properties.TextAlignment; +import org.quartz.Job; +import org.quartz.JobDataMap; +import org.quartz.JobExecutionContext; +import org.quartz.JobExecutionException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import javax.mail.MessagingException; +import java.io.IOException; +import java.util.Optional; +import br.edu.utfpr.servicebook.model.entity.User; +import com.itextpdf.kernel.pdf.PdfDocument; +import com.itextpdf.kernel.pdf.PdfWriter; +import com.itextpdf.layout.Document; +import com.itextpdf.layout.element.Paragraph; + +import java.io.ByteArrayOutputStream; +import com.itextpdf.kernel.pdf.PdfDocument; +import com.itextpdf.kernel.pdf.PdfWriter; +import com.itextpdf.layout.Document; +import com.itextpdf.layout.element.Paragraph; +import com.itextpdf.layout.element.Text; +import org.quartz.JobDataMap; +import org.quartz.JobExecutionContext; +import org.quartz.JobExecutionException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class SendEmailVoucher implements Job { + + public static final String PAYMENT_KEY = "token"; + public static final Long CLIENT_ID = Long.valueOf(0); + public static final Long PROFESSIONAL_ID = Long.valueOf(0); + public static final String SERVICE_KEY = "recipient_service"; + public static final String DATE_KEY = "recipient_date"; + + public static final String VOUCHER_KEY = "recipient_voucher"; + + @Autowired + private EmailSenderService emailSenderService; + + @Autowired + private UserService userService; + + @Override + public void execute(JobExecutionContext context) throws JobExecutionException { + JobDataMap jobDataMap = context.getJobDetail().getJobDataMap(); + + String email1 = "thryssai@gmail.com"; + + String code = (String) jobDataMap.get(SendEmailVoucher.PAYMENT_KEY); + String voucher = (String) jobDataMap.get(SendEmailVoucher.VOUCHER_KEY); + + Long clientId = (Long) jobDataMap.get(SendEmailVoucher.CLIENT_ID.toString()); + Optional oUser = userService.findById(clientId); + + Long professionalId = (Long) jobDataMap.get(SendEmailVoucher.PROFESSIONAL_ID.toString()); + Optional oProfessional = userService.findById(professionalId); + + String service = (String) jobDataMap.get(SendEmailVoucher.SERVICE_KEY); + + String date = (String) jobDataMap.get(SendEmailVoucher.DATE_KEY); + + String emailClient = (String) oUser.get().getEmail(); + String emailProfessional = (String) oProfessional.get().getEmail(); + + String text = "" + + "

Olá, "+ email1 +"

" + + "

Segue o voucher por anexo que deverá ser apresentado no momento da realização do serviço.

" + + "

Qualquer informação pode ser obtida diretamente com o profissional, através do contato disponibilizado na plataforma.

" + + "

Ver o meu Voucher

"+ + "

Atenciosamente,

" + + "

Equipe ServiceBook.

" + + ""; + + String textProfessional = "" + + "

Olá, "+ email1 +"

" + + "

Segue o voucher por anexo que deverá ser apresentado pelo cliente no momento da realização do serviço.

" + + "

Serviço solicitado por: "+ oUser.get().getName() +".

" + + "

Ele está disponível no seguinte link:

" + + "

Ver o meu Voucher

"+ + "

Atenciosamente,

" + + "

Equipe ServiceBook.

" + + ""; + + try { + + emailSenderService.sendHTMLEmail(email1, "Service Book - Comprovante de Pagamento", text); + emailSenderService.sendHTMLEmail(email1, "Service Book - Comprovante de Pagamento", textProfessional); + + } catch (MessagingException e) { + System.out.println(e.getMessage()); + } + } + + public byte[] generatePDF(String code, String service, String date, String professional, String client) throws JobExecutionException { + // criar PDF + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + PdfWriter pdfWriter = new PdfWriter(outputStream); + PdfDocument pdfDocument = new PdfDocument(pdfWriter); + Document document = new Document(pdfDocument); + + Text titleText = new Text("Comprovante de Pagamento\n\n") + .setFontSize(20) + .setBold(); + Paragraph titleParagraph = new Paragraph(titleText) + .setTextAlignment(TextAlignment.CENTER); + document.add(titleParagraph); + + Paragraph contentParagraph = new Paragraph() + .add(new Text("Voucher: ").setBold()) + .add(new Text(code)) + .add("\n") + .add(new Text("Serviço: ").setBold()) + .add(new Text(service)) + .add("\n") + .add(new Text("Data de Validade: ").setBold()) + .add(new Text(date)) + .add("\n\n") + .add(new Text("Profissional: : ").setBold()) + .add(new Text(professional)) + .add("\n\n") + .add(new Text("Cliente: ").setBold()) + .add(new Text(client)) + .add("\n\n"); + document.add(contentParagraph); + + document.close(); + return outputStream.toByteArray(); + } +} diff --git a/src/main/java/br/edu/utfpr/servicebook/model/dto/ClientMinDTO.java b/src/main/java/br/edu/utfpr/servicebook/model/dto/ClientMinDTO.java index 395bfc48..5feafebc 100644 --- a/src/main/java/br/edu/utfpr/servicebook/model/dto/ClientMinDTO.java +++ b/src/main/java/br/edu/utfpr/servicebook/model/dto/ClientMinDTO.java @@ -1,5 +1,6 @@ package br.edu.utfpr.servicebook.model.dto; +import br.edu.utfpr.servicebook.util.IWizardDTO; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @@ -9,9 +10,9 @@ @Data @NoArgsConstructor @AllArgsConstructor -public class ClientMinDTO implements Serializable { +public class ClientMinDTO extends UserDTO implements IWizardDTO, Serializable{ private String name; - private AddressMinDTO address; +// private AddressMinDTO address; } diff --git a/src/main/java/br/edu/utfpr/servicebook/model/dto/JobRequestMinDTO.java b/src/main/java/br/edu/utfpr/servicebook/model/dto/JobRequestMinDTO.java index 8e40a8fc..095225cb 100644 --- a/src/main/java/br/edu/utfpr/servicebook/model/dto/JobRequestMinDTO.java +++ b/src/main/java/br/edu/utfpr/servicebook/model/dto/JobRequestMinDTO.java @@ -19,6 +19,8 @@ public class JobRequestMinDTO implements Serializable { private ExpertiseDTO expertiseDTO; + private ClientDTO clientDTO; + private String dateCreated; private String dateTarget; diff --git a/src/main/java/br/edu/utfpr/servicebook/model/dto/PaymentDTO.java b/src/main/java/br/edu/utfpr/servicebook/model/dto/PaymentDTO.java new file mode 100644 index 00000000..be5a0cdb --- /dev/null +++ b/src/main/java/br/edu/utfpr/servicebook/model/dto/PaymentDTO.java @@ -0,0 +1,18 @@ +package br.edu.utfpr.servicebook.model.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotEmpty; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class PaymentDTO { + @NotEmpty(message = "O identificador do pagamento é obrigatório") + private Integer paymentId; + + @NotEmpty(message = "O status do pagamento é obrigatório") + private String status; +} diff --git a/src/main/java/br/edu/utfpr/servicebook/model/dto/PaymentJobDTO.java b/src/main/java/br/edu/utfpr/servicebook/model/dto/PaymentJobDTO.java new file mode 100644 index 00000000..673cb931 --- /dev/null +++ b/src/main/java/br/edu/utfpr/servicebook/model/dto/PaymentJobDTO.java @@ -0,0 +1,14 @@ +package br.edu.utfpr.servicebook.model.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class PaymentJobDTO { + private Long id; + private Long jobRequestId; + private Long paymentId; +} diff --git a/src/main/java/br/edu/utfpr/servicebook/model/dto/PaymentVoucherDTO.java b/src/main/java/br/edu/utfpr/servicebook/model/dto/PaymentVoucherDTO.java new file mode 100644 index 00000000..43ce8d81 --- /dev/null +++ b/src/main/java/br/edu/utfpr/servicebook/model/dto/PaymentVoucherDTO.java @@ -0,0 +1,22 @@ +package br.edu.utfpr.servicebook.model.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.ToString; + +import java.io.Serializable; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@ToString +public class PaymentVoucherDTO implements Serializable { + private Long id; + private Long paymentId; + private Long clientId; + private Long professionalId; + private Long jobRequestId; + + private String code; +} diff --git a/src/main/java/br/edu/utfpr/servicebook/model/dto/ProfessionalServiceOfferingDTO.java b/src/main/java/br/edu/utfpr/servicebook/model/dto/ProfessionalServiceOfferingDTO.java index 01c3d995..ba995c5f 100644 --- a/src/main/java/br/edu/utfpr/servicebook/model/dto/ProfessionalServiceOfferingDTO.java +++ b/src/main/java/br/edu/utfpr/servicebook/model/dto/ProfessionalServiceOfferingDTO.java @@ -1,11 +1,13 @@ package br.edu.utfpr.servicebook.model.dto; +import br.edu.utfpr.servicebook.model.entity.ProfessionalServicePackageOffering; import br.edu.utfpr.servicebook.model.entity.Service; import br.edu.utfpr.servicebook.model.entity.User; import lombok.Data; import lombok.NoArgsConstructor; import javax.persistence.*; +import java.util.Set; /** * Classe que representa um serviço adicionado por um profissional ao seu portfólio. @@ -19,6 +21,13 @@ public class ProfessionalServiceOfferingDTO { private Long id; + public enum Type { + INDIVIDUAL, + COMBINED_PACKAGE, + SIMPLE_PACKAGE + } + + private Type type; /** * Nome do serviço. * O profissional pode customizar o nome do serviço cadastrado pelo administrador de várias maneiras, dependendo @@ -34,6 +43,17 @@ public class ProfessionalServiceOfferingDTO { * Caso ele não especifique a descrição do serviço, a descrição do serviço cadastrado pelo administrador será usada. */ private String description; + private Set descriptions; + + /** + * Unidade de preço do serviço. + */ + private String unit; + + /** + * Duração do serviço. + */ + private String duration; /** * Serviço cadastrado pelo administrador. @@ -44,6 +64,10 @@ public class ProfessionalServiceOfferingDTO { private Long serviceId; + /** + * Preço do serviço individual. + */ + private Long price; /** * Profissional que oferece o serviço. */ diff --git a/src/main/java/br/edu/utfpr/servicebook/model/dto/ProfessionalServicePackageOfferingDTO.java b/src/main/java/br/edu/utfpr/servicebook/model/dto/ProfessionalServicePackageOfferingDTO.java new file mode 100644 index 00000000..d0e9e27e --- /dev/null +++ b/src/main/java/br/edu/utfpr/servicebook/model/dto/ProfessionalServicePackageOfferingDTO.java @@ -0,0 +1,67 @@ +package br.edu.utfpr.servicebook.model.dto; + +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.HashSet; +import java.util.Set; + +@Data +@NoArgsConstructor +public class ProfessionalServicePackageOfferingDTO { + private Long id; + + public enum Type { + INDIVIDUAL, + COMBINED_PACKAGE, + SIMPLE_PACKAGE + } + + private ProfessionalServiceOfferingDTO.Type type; + /** + * Nome do serviço. + * O profissional pode customizar o nome do serviço cadastrado pelo administrador de várias maneiras, dependendo + * do tipo de particularidade que o seu serviço tem. + * Caso ele não especifique o nome do serviço, o nome do serviço cadastrado pelo administrador será usado. + */ + private String name; + + /** + * Descrição do serviço em primeira pessoa. + * O profissional pode customizar a descrição do serviço cadastrado pelo administrador de várias maneiras, dependendo + * do tipo de particularidade que o seu serviço tem. + * Caso ele não especifique a descrição do serviço, a descrição do serviço cadastrado pelo administrador será usada. + */ + private String description; + + /** + * Unidade de preço do serviço. + */ + private String unit; + + /** + * Duração do serviço. + */ + private String duration; + + private Integer amount; + + /** + * Serviço cadastrado pelo administrador. + * O profissional pode customizar a descrição do serviço cadastrado pelo administrador de várias maneiras, dependendo + * do tipo de particularidade que o seu serviço tem. + */ + private ServiceDTO service; + private ExpertiseDTO expertise; + + private Long serviceId; + private Long expertiseId; + private Long price; + + /** + * Profissional que oferece o serviço. + */ + private UserDTO user; + + private Long userId; +} diff --git a/src/main/java/br/edu/utfpr/servicebook/model/entity/DurationService.java b/src/main/java/br/edu/utfpr/servicebook/model/entity/DurationService.java new file mode 100644 index 00000000..6baf0682 --- /dev/null +++ b/src/main/java/br/edu/utfpr/servicebook/model/entity/DurationService.java @@ -0,0 +1,23 @@ +package br.edu.utfpr.servicebook.model.entity; + +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; + +import javax.persistence.*; + +@Data +@NoArgsConstructor +@RequiredArgsConstructor +@Table(name = "duration_services") +@Entity +public class DurationService { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @NonNull + @Column(unique = true) + private String name; +} diff --git a/src/main/java/br/edu/utfpr/servicebook/model/entity/Payment.java b/src/main/java/br/edu/utfpr/servicebook/model/entity/Payment.java new file mode 100644 index 00000000..4f8eac0f --- /dev/null +++ b/src/main/java/br/edu/utfpr/servicebook/model/entity/Payment.java @@ -0,0 +1,31 @@ +package br.edu.utfpr.servicebook.model.entity; + +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; + +import javax.persistence.*; +import java.util.List; + +@Data +@NoArgsConstructor +@RequiredArgsConstructor +@Table(name = "payments") +@Entity +public class Payment { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @NonNull + @Column(unique = true) + private Integer paymentId; + + @NonNull + @Column() + private String status; + + @OneToMany(mappedBy = "payment", cascade = CascadeType.ALL) + private List paymentJobs; +} \ No newline at end of file diff --git a/src/main/java/br/edu/utfpr/servicebook/model/entity/PaymentJobRequest.java b/src/main/java/br/edu/utfpr/servicebook/model/entity/PaymentJobRequest.java new file mode 100644 index 00000000..57fa8c8d --- /dev/null +++ b/src/main/java/br/edu/utfpr/servicebook/model/entity/PaymentJobRequest.java @@ -0,0 +1,32 @@ +package br.edu.utfpr.servicebook.model.entity; + +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.NonNull; + +import javax.persistence.*; +import java.util.Date; +import java.util.List; +@Data +@NoArgsConstructor +@Table(name = "payments_jobRequests") +@Entity +public class PaymentJobRequest { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @NonNull + private Long jobRequestId; + + @ManyToOne + @JoinColumn(name = "payment_id", nullable = false) + private Payment payment; + + @ManyToOne + @JoinColumn(name = "jobrequest_id") + private JobRequest jobRequest; + + @Temporal(TemporalType.DATE) + private Date dateCreated; +} diff --git a/src/main/java/br/edu/utfpr/servicebook/model/entity/PaymentVoucher.java b/src/main/java/br/edu/utfpr/servicebook/model/entity/PaymentVoucher.java new file mode 100644 index 00000000..c01c7686 --- /dev/null +++ b/src/main/java/br/edu/utfpr/servicebook/model/entity/PaymentVoucher.java @@ -0,0 +1,32 @@ +package br.edu.utfpr.servicebook.model.entity; + +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.persistence.*; +import java.util.Date; + +@Data +@NoArgsConstructor +@Table(name = "payment_vouchers") +@Entity +public class PaymentVoucher { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + private String code; + + @ManyToOne + @JoinColumn(name = "client_id") + private User client; + + @ManyToOne + @JoinColumn(name = "professional_id") + private User professional; + + @ManyToOne + @JoinColumn(name = "jobrequest_id") + private JobRequest jobRequest; + +} diff --git a/src/main/java/br/edu/utfpr/servicebook/model/entity/PriceUnit.java b/src/main/java/br/edu/utfpr/servicebook/model/entity/PriceUnit.java new file mode 100644 index 00000000..68950fc4 --- /dev/null +++ b/src/main/java/br/edu/utfpr/servicebook/model/entity/PriceUnit.java @@ -0,0 +1,23 @@ +package br.edu.utfpr.servicebook.model.entity; + +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; + +import javax.persistence.*; + +@Data +@NoArgsConstructor +@RequiredArgsConstructor +@Table(name = "price_units") +@Entity +public class PriceUnit { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @NonNull + @Column(unique = true) + private String name; +} diff --git a/src/main/java/br/edu/utfpr/servicebook/model/entity/ProfessionalServiceOffering.java b/src/main/java/br/edu/utfpr/servicebook/model/entity/ProfessionalServiceOffering.java index ff6474ec..0291489b 100644 --- a/src/main/java/br/edu/utfpr/servicebook/model/entity/ProfessionalServiceOffering.java +++ b/src/main/java/br/edu/utfpr/servicebook/model/entity/ProfessionalServiceOffering.java @@ -23,6 +23,19 @@ public class ProfessionalServiceOffering { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; + public enum Type { + INDIVIDUAL, + COMBINED_PACKAGE, + SIMPLE_PACKAGE + } + + /** + * Tipo de anúncio. + */ + @Enumerated(EnumType.STRING) + private ProfessionalServiceOffering.Type type; + + /** * Nome do serviço. * O profissional pode customizar o nome do serviço cadastrado pelo administrador de várias maneiras, dependendo @@ -46,6 +59,16 @@ public class ProfessionalServiceOffering { */ private Long price; + /** + * Unidade de preço do serviço. + */ + private String unit; + + /** + * Duração do serviço. + */ + private String duration; + /** * Serviço cadastrado pelo administrador. * O profissional pode customizar a descrição do serviço cadastrado pelo administrador de várias maneiras, dependendo diff --git a/src/main/java/br/edu/utfpr/servicebook/model/entity/ProfessionalServiceOfferingAdItemPK.java b/src/main/java/br/edu/utfpr/servicebook/model/entity/ProfessionalServiceOfferingAdItemPK.java index a8aa64a2..ad03b0ab 100644 --- a/src/main/java/br/edu/utfpr/servicebook/model/entity/ProfessionalServiceOfferingAdItemPK.java +++ b/src/main/java/br/edu/utfpr/servicebook/model/entity/ProfessionalServiceOfferingAdItemPK.java @@ -16,6 +16,7 @@ @AllArgsConstructor @Embeddable public class ProfessionalServiceOfferingAdItemPK implements Serializable { + Long professionalServiceOfferingId; Long professionalServiceOfferingAdId; diff --git a/src/main/java/br/edu/utfpr/servicebook/model/entity/ProfessionalServicePackageOffering.java b/src/main/java/br/edu/utfpr/servicebook/model/entity/ProfessionalServicePackageOffering.java index 88bc74f1..1a043cd5 100644 --- a/src/main/java/br/edu/utfpr/servicebook/model/entity/ProfessionalServicePackageOffering.java +++ b/src/main/java/br/edu/utfpr/servicebook/model/entity/ProfessionalServicePackageOffering.java @@ -64,6 +64,21 @@ public enum Type { */ private Long price; + /** + * Unidade de preço do serviço. + */ + private String unit; + + /** + * Duração do serviço. + */ + private String duration; + + /** + * Quantidade, para o pacote de serviços. + * */ + private Integer amount; + /** * Usuário que criou o anúncio. */ @@ -75,4 +90,13 @@ public enum Type { */ @ManyToOne private Expertise expertise; + + /** + * Serviço cadastrado pelo administrador. + * O profissional pode customizar a descrição do serviço cadastrado pelo administrador de várias maneiras, dependendo + * do tipo de particularidade que o seu serviço tem. + */ + @ManyToOne + @JoinColumn(name = "service_id") + private Service service; } diff --git a/src/main/java/br/edu/utfpr/servicebook/model/mapper/ClientMapper.java b/src/main/java/br/edu/utfpr/servicebook/model/mapper/ClientMapper.java index c1e226a7..dddd63e5 100644 --- a/src/main/java/br/edu/utfpr/servicebook/model/mapper/ClientMapper.java +++ b/src/main/java/br/edu/utfpr/servicebook/model/mapper/ClientMapper.java @@ -1,7 +1,11 @@ package br.edu.utfpr.servicebook.model.mapper; import br.edu.utfpr.servicebook.model.dto.ClientDTO; +import br.edu.utfpr.servicebook.model.dto.ClientMinDTO; +import br.edu.utfpr.servicebook.model.dto.ExpertiseMinDTO; +import br.edu.utfpr.servicebook.model.entity.Expertise; import br.edu.utfpr.servicebook.model.entity.Individual; +import br.edu.utfpr.servicebook.model.entity.User; import org.modelmapper.ModelMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -16,7 +20,10 @@ public ClientDTO toDto(Individual entity){ ClientDTO dto = mapper.map(entity, ClientDTO.class); return dto; } - + public ClientDTO toDto1(User entity){ + ClientDTO dto = mapper.map(entity, ClientDTO.class); + return dto; + } public ClientDTO toResponseDto(Individual entity) { ClientDTO dto = mapper.map(entity, ClientDTO.class); return dto; @@ -26,4 +33,9 @@ public Individual toEntity(ClientDTO dto) { Individual entity = mapper.map(dto, Individual.class); return entity; } + + public ClientMinDTO toMinDto(User entity){ + ClientMinDTO dto = mapper.map(entity, ClientMinDTO.class); + return dto; + } } \ No newline at end of file diff --git a/src/main/java/br/edu/utfpr/servicebook/model/mapper/JobRequestMapper.java b/src/main/java/br/edu/utfpr/servicebook/model/mapper/JobRequestMapper.java index 80a722b7..e2ee128d 100644 --- a/src/main/java/br/edu/utfpr/servicebook/model/mapper/JobRequestMapper.java +++ b/src/main/java/br/edu/utfpr/servicebook/model/mapper/JobRequestMapper.java @@ -25,6 +25,8 @@ public class JobRequestMapper { @Autowired private ExpertiseMapper expertiseMapper; + @Autowired + private ClientMapper clientMapper; public JobRequestDTO toDto(JobRequest entity) { return mapper.map(entity, JobRequestDTO.class); } @@ -48,6 +50,7 @@ public JobRequestMinDTO toMinDto(JobRequest entity, Long amountOfCandidates) { JobRequestMinDTO dto = mapper.map(entity, JobRequestMinDTO.class); dto.setAmountOfCandidates(amountOfCandidates); dto.setExpertiseDTO(expertiseMapper.toDto(entity.getExpertise())); +// dto.setClientDTO(clientMapper.toDto1(entity.getUser())); dto.setDateCreated(this.dateTimeFormatter.format(entity.getDateCreated())); dto.setDateTarget(this.dateTimeFormatter.format(entity.getDateTarget())); diff --git a/src/main/java/br/edu/utfpr/servicebook/model/mapper/PaymentJobMapper.java b/src/main/java/br/edu/utfpr/servicebook/model/mapper/PaymentJobMapper.java new file mode 100644 index 00000000..09621867 --- /dev/null +++ b/src/main/java/br/edu/utfpr/servicebook/model/mapper/PaymentJobMapper.java @@ -0,0 +1,24 @@ +package br.edu.utfpr.servicebook.model.mapper; + +import br.edu.utfpr.servicebook.model.dto.PaymentJobDTO; +import br.edu.utfpr.servicebook.model.dto.PaymentVoucherDTO; +import br.edu.utfpr.servicebook.model.entity.PaymentJobRequest; +import br.edu.utfpr.servicebook.model.entity.PaymentVoucher; +import org.modelmapper.ModelMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class PaymentJobMapper { + @Autowired + private ModelMapper mapper; + + public PaymentJobDTO toDTO(PaymentJobRequest entity) { + return mapper.map(entity, PaymentJobDTO.class); + } + + public PaymentJobRequest toEntity(PaymentJobDTO dto) { + PaymentJobRequest entity = mapper.map(dto, PaymentJobRequest.class); + return entity; + } +} diff --git a/src/main/java/br/edu/utfpr/servicebook/model/mapper/PaymentMapper.java b/src/main/java/br/edu/utfpr/servicebook/model/mapper/PaymentMapper.java new file mode 100644 index 00000000..a961716c --- /dev/null +++ b/src/main/java/br/edu/utfpr/servicebook/model/mapper/PaymentMapper.java @@ -0,0 +1,27 @@ +package br.edu.utfpr.servicebook.model.mapper; + + +import org.modelmapper.ModelMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import br.edu.utfpr.servicebook.model.dto.PaymentDTO; +import br.edu.utfpr.servicebook.model.entity.Payment; + +@Component +public class PaymentMapper { + + @Autowired + private ModelMapper mapper; + + public PaymentDTO toDto(Payment entity) { + PaymentDTO dto = mapper.map(entity, PaymentDTO.class); + return dto; + } + + public Payment toEntity(PaymentDTO dto) { + Payment entity = mapper.map(dto, Payment.class); + return entity; + } + +} diff --git a/src/main/java/br/edu/utfpr/servicebook/model/mapper/PaymentVoucherMapper.java b/src/main/java/br/edu/utfpr/servicebook/model/mapper/PaymentVoucherMapper.java new file mode 100644 index 00000000..886ec30d --- /dev/null +++ b/src/main/java/br/edu/utfpr/servicebook/model/mapper/PaymentVoucherMapper.java @@ -0,0 +1,24 @@ +package br.edu.utfpr.servicebook.model.mapper; + +import br.edu.utfpr.servicebook.model.dto.PaymentVoucherDTO; +import br.edu.utfpr.servicebook.model.dto.ProfessionalExpertiseDTO; +import br.edu.utfpr.servicebook.model.entity.PaymentVoucher; +import br.edu.utfpr.servicebook.model.entity.ProfessionalExpertise; +import org.modelmapper.ModelMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class PaymentVoucherMapper { + @Autowired + private ModelMapper mapper; + + public PaymentVoucherDTO toDTO(PaymentVoucher entity) { + return mapper.map(entity, PaymentVoucherDTO.class); + } + + public PaymentVoucher toEntity(PaymentVoucherDTO dto) { + PaymentVoucher entity = mapper.map(dto, PaymentVoucher.class); + return entity; + } +} diff --git a/src/main/java/br/edu/utfpr/servicebook/model/mapper/ProfessionalServiceOfferingMapper.java b/src/main/java/br/edu/utfpr/servicebook/model/mapper/ProfessionalServiceOfferingMapper.java index 80956a23..60a6f007 100644 --- a/src/main/java/br/edu/utfpr/servicebook/model/mapper/ProfessionalServiceOfferingMapper.java +++ b/src/main/java/br/edu/utfpr/servicebook/model/mapper/ProfessionalServiceOfferingMapper.java @@ -1,9 +1,6 @@ package br.edu.utfpr.servicebook.model.mapper; -import br.edu.utfpr.servicebook.model.dto.AddressDTO; -import br.edu.utfpr.servicebook.model.dto.ProfessionalServiceOfferingDTO; -import br.edu.utfpr.servicebook.model.entity.Address; -import br.edu.utfpr.servicebook.model.entity.City; +import br.edu.utfpr.servicebook.model.dto.*; import br.edu.utfpr.servicebook.model.entity.ProfessionalServiceOffering; import org.modelmapper.ModelMapper; import org.springframework.beans.factory.annotation.Autowired; @@ -25,4 +22,8 @@ public ProfessionalServiceOffering toEntity(ProfessionalServiceOfferingDTO dto){ return entity; } + public ProfessionalServiceOfferingDTO toSearchItemDto(ProfessionalServiceOffering entity){ + ProfessionalServiceOfferingDTO dto = mapper.map(entity, ProfessionalServiceOfferingDTO.class); + return dto; + } } diff --git a/src/main/java/br/edu/utfpr/servicebook/model/repository/IndividualRepository.java b/src/main/java/br/edu/utfpr/servicebook/model/repository/IndividualRepository.java index 93828008..3599f030 100644 --- a/src/main/java/br/edu/utfpr/servicebook/model/repository/IndividualRepository.java +++ b/src/main/java/br/edu/utfpr/servicebook/model/repository/IndividualRepository.java @@ -1,6 +1,7 @@ package br.edu.utfpr.servicebook.model.repository; import br.edu.utfpr.servicebook.model.entity.Individual; +import br.edu.utfpr.servicebook.model.entity.Service; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; @@ -53,4 +54,16 @@ Page findDistinctByTermIgnoreCaseWithPagination( "or lower(p.description) like lower(concat('%', :term, '%')) " + "or lower(pe.expertise.name) like lower(concat('%', :term, '%'))") List findDistinctByTermIgnoreCase(String term); + + @Query("select p from Individual p left join ProfessionalServiceOffering pe on p.id = pe.user.id where " + + "pe.service = :term") + Page findAllIndividualsByService( + Service term, + Pageable pageable); + + @Query("select p from Individual p left join ProfessionalExpertise pe on p.id = pe.professional.id " + + "where pe.expertise.id = 4") + List findAllIndividualsAutonomosByService( + Long term, + Pageable pageable); } \ No newline at end of file diff --git a/src/main/java/br/edu/utfpr/servicebook/model/repository/PaymentJobRepository.java b/src/main/java/br/edu/utfpr/servicebook/model/repository/PaymentJobRepository.java new file mode 100644 index 00000000..4125693f --- /dev/null +++ b/src/main/java/br/edu/utfpr/servicebook/model/repository/PaymentJobRepository.java @@ -0,0 +1,22 @@ +package br.edu.utfpr.servicebook.model.repository; + +import br.edu.utfpr.servicebook.model.entity.JobRequest; +import br.edu.utfpr.servicebook.model.entity.PaymentJobRequest; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; +import java.util.Optional; + +@Repository +public interface PaymentJobRepository extends JpaRepository { + List findAll(); + + Page findAll(Pageable pageable); + + List findAllById(Iterable longs); + + Optional findByJobRequest(JobRequest id); +} diff --git a/src/main/java/br/edu/utfpr/servicebook/model/repository/PaymentRepository.java b/src/main/java/br/edu/utfpr/servicebook/model/repository/PaymentRepository.java new file mode 100644 index 00000000..eff63f00 --- /dev/null +++ b/src/main/java/br/edu/utfpr/servicebook/model/repository/PaymentRepository.java @@ -0,0 +1,13 @@ +package br.edu.utfpr.servicebook.model.repository; + +import br.edu.utfpr.servicebook.model.entity.Payment; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface PaymentRepository extends JpaRepository{ + + +} + diff --git a/src/main/java/br/edu/utfpr/servicebook/model/repository/PaymentVoucherRepository.java b/src/main/java/br/edu/utfpr/servicebook/model/repository/PaymentVoucherRepository.java new file mode 100644 index 00000000..db2bf473 --- /dev/null +++ b/src/main/java/br/edu/utfpr/servicebook/model/repository/PaymentVoucherRepository.java @@ -0,0 +1,22 @@ +package br.edu.utfpr.servicebook.model.repository; + +import br.edu.utfpr.servicebook.model.entity.PaymentVoucher; +import br.edu.utfpr.servicebook.model.entity.Service; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; +import java.util.Optional; + +@Repository +public interface PaymentVoucherRepository extends JpaRepository { + + List findAll(); + + + Page findAll(Pageable pageable); + + List findAllById(Iterable longs); +} diff --git a/src/main/java/br/edu/utfpr/servicebook/model/repository/ProfessionalServiceOfferingAdItemRepository.java b/src/main/java/br/edu/utfpr/servicebook/model/repository/ProfessionalServiceOfferingAdItemRepository.java index 9abab248..f3229144 100644 --- a/src/main/java/br/edu/utfpr/servicebook/model/repository/ProfessionalServiceOfferingAdItemRepository.java +++ b/src/main/java/br/edu/utfpr/servicebook/model/repository/ProfessionalServiceOfferingAdItemRepository.java @@ -1,9 +1,8 @@ package br.edu.utfpr.servicebook.model.repository; -import br.edu.utfpr.servicebook.model.entity.ProfessionalServicePackageOffering; -import br.edu.utfpr.servicebook.model.entity.ProfessionalServiceOfferingAdItem; -import br.edu.utfpr.servicebook.model.entity.ProfessionalServiceOfferingAdItemPK; +import br.edu.utfpr.servicebook.model.entity.*; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; import org.springframework.stereotype.Repository; import java.util.List; @@ -17,9 +16,23 @@ public interface ProfessionalServiceOfferingAdItemRepository extends JpaReposito */ List findAllByProfessionalServicePackageOffering(ProfessionalServicePackageOffering professionalServicePackageOffering); + /** + * Retorna os serviços que o usuário possui. + * @param user + * @return + */ +// @Query("SELECT u FROM ProfessionalServiceOffering u WHERE EXISTS (SELECT pe FROM ProfessionalServicePackageOffering pe WHERE pe.user = :user)") +// List findProfessionalServiceOfferingAdItemsByUser(User user); +// @Query("SELECT u FROM ProfessionalServiceOffering u JOIN u.packageOfferings pe WHERE pe.user = :user") +// List findProfessionalServiceOfferingAdItemsByUser(User user); +// + @Query("SELECT u FROM ProfessionalServiceOfferingAdItem u JOIN u.professionalServiceOffering pso JOIN u.professionalServicePackageOffering jspo") + List findProfessionalServiceOfferingAdItemsByUserJoin(User user); - - + @Query("SELECT psa FROM ProfessionalServiceOfferingAdItem psa " + + "JOIN FETCH psa.professionalServiceOffering pso WHERE pso.user = :user") +// List findDistinctByProfessionalServiceOfferingAdItemsByProfessionalServiceOfferingEndingWithAndProfessionalServicePackageOffering(User user); + List findProfessionalServiceOfferingAdItemsWithRelatedEntities(User user); } diff --git a/src/main/java/br/edu/utfpr/servicebook/model/repository/ProfessionalServiceOfferingRepository.java b/src/main/java/br/edu/utfpr/servicebook/model/repository/ProfessionalServiceOfferingRepository.java index b792a723..0d125a0d 100644 --- a/src/main/java/br/edu/utfpr/servicebook/model/repository/ProfessionalServiceOfferingRepository.java +++ b/src/main/java/br/edu/utfpr/servicebook/model/repository/ProfessionalServiceOfferingRepository.java @@ -1,6 +1,8 @@ package br.edu.utfpr.servicebook.model.repository; import br.edu.utfpr.servicebook.model.entity.*; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.stereotype.Repository; @@ -18,6 +20,8 @@ public interface ProfessionalServiceOfferingRepository extends JpaRepository findProfessionalServiceOfferingByUser(User user); + public List findFirst3ByUserAndType(User user, Enum type); + public List findByUserAndType(User user, Enum type); /** * Busca todas os serviços de um profissional @@ -63,6 +67,42 @@ public interface ProfessionalServiceOfferingRepository extends JpaRepository findProfessionalServiceOfferingByName(String name); + @Query("select distinct p from ProfessionalServiceOffering p left join Service pe on p.service = pe where " + + "lower(p.name) like lower(concat('%', :term, '%'))" + + "or lower(p.description) like lower(concat('%', :term, '%')) " + + "or lower(pe.expertise.name) like lower(concat('%', :term, '%'))") + Page findDistinctByTermIgnoreCaseWithPagination( + String term, + Pageable pageable); + @Query("SELECT e FROM ProfessionalServiceOffering e WHERE e.service = :id") + public Optional findProfessionalServiceOfferingById(Long id); + /** + * Busca o serviço atraves dos anuncios gravados. + * @param term + * @param pageable + * @return + */ + @Query("select pe from Individual p left join ProfessionalServiceOffering pe on p = pe.user where " + + "pe.service = :term") + Page findAllIndividualsByService( + Service term, + Pageable pageable); + + /** + * Retorna os serviços que o usuário possui. + * @param user + * @return + */ + @Query("SELECT u FROM ProfessionalServiceOfferingAdItem u WHERE EXISTS (SELECT pe FROM ProfessionalServiceOffering pe WHERE pe.user = :user)") + List findProfessionalServiceOfferingAdItemsByUser(User user); + + @Query("SELECT u FROM ProfessionalServiceOffering u JOIN ProfessionalServiceOfferingAdItem r WHERE r.professionalServiceOffering.id = u.id") + public List findProfessionalServiceOfferingAdItemsByUserJoin(User user); + @Query("SELECT u FROM ProfessionalServiceOfferingAdItem u JOIN FETCH u.professionalServicePackageOffering") + List findDistinctProfessionalServiceOfferings(); + + @Query("SELECT e FROM ProfessionalServiceOffering e WHERE e.user.id = :userId AND e.service.expertise.id = :expertiseId") + public Optional findProfessionalServiceOfferingByExpertiseAAndUser(Long userId, Long expertiseId); } diff --git a/src/main/java/br/edu/utfpr/servicebook/model/repository/ProfessionalServicePackageOfferingRepository.java b/src/main/java/br/edu/utfpr/servicebook/model/repository/ProfessionalServicePackageOfferingRepository.java index ab0a9054..7fcfdd2d 100644 --- a/src/main/java/br/edu/utfpr/servicebook/model/repository/ProfessionalServicePackageOfferingRepository.java +++ b/src/main/java/br/edu/utfpr/servicebook/model/repository/ProfessionalServicePackageOfferingRepository.java @@ -24,5 +24,10 @@ public interface ProfessionalServicePackageOfferingRepository extends JpaReposit /** * Busca os anúncios de um dado profissional. */ - public List findAllByUser(User user); + public List findFirst3ByUserAndType(User user, Enum type); + + public List findByUserAndType(User user, Enum type); + + @Query("SELECT po FROM ProfessionalServiceOfferingAdItem poa INNER JOIN ProfessionalServiceOffering po ON poa.professionalServiceOffering = po WHERE po.user = :userId") + public List findAllByCombinedAndItems(User userId); } diff --git a/src/main/java/br/edu/utfpr/servicebook/service/EmailSenderService.java b/src/main/java/br/edu/utfpr/servicebook/service/EmailSenderService.java index 1dadb022..d6f389ce 100644 --- a/src/main/java/br/edu/utfpr/servicebook/service/EmailSenderService.java +++ b/src/main/java/br/edu/utfpr/servicebook/service/EmailSenderService.java @@ -2,14 +2,17 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; +import org.springframework.core.io.ByteArrayResource; import org.springframework.mail.SimpleMailMessage; import org.springframework.mail.javamail.JavaMailSender; +import org.springframework.mail.javamail.MimeMessageHelper; import org.springframework.stereotype.Service; import javax.mail.Message; import javax.mail.MessagingException; import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeMessage; +import java.io.IOException; @Service public class EmailSenderService { @@ -53,4 +56,18 @@ public void sendHTMLEmail(String to, String subject, String html) throws Messagi mailSender.send(message); } + public void sendEmailWithAttachment(String to, String subject, String html, byte[] pdfBytes, String pdfFileName) throws MessagingException, IOException { + MimeMessage message = mailSender.createMimeMessage(); + MimeMessageHelper helper = new MimeMessageHelper(message, true); + + helper.setTo(to); + helper.setSubject(subject); + helper.setText(html, true); + + // Adicionar o anexo ao email + helper.addAttachment(pdfFileName, new ByteArrayResource(pdfBytes)); + + mailSender.send(message); + + } } diff --git a/src/main/java/br/edu/utfpr/servicebook/service/IndividualService.java b/src/main/java/br/edu/utfpr/servicebook/service/IndividualService.java index 59d2fa0f..9d9f93a2 100644 --- a/src/main/java/br/edu/utfpr/servicebook/service/IndividualService.java +++ b/src/main/java/br/edu/utfpr/servicebook/service/IndividualService.java @@ -129,7 +129,15 @@ public User getAuthenticated(){ return null; } + public Page findAllIndividualsByService(br.edu.utfpr.servicebook.model.entity.Service searchTerm, Integer page, Integer size){ + PageRequest pageRequest = PageRequest.of(page - 1, size); + return this.individualRepository.findAllIndividualsByService(searchTerm, pageRequest); + } + public List findAllIndividualsAutonomosByService(Long searchTerm, Integer page, Integer size){ + PageRequest pageRequest = PageRequest.of(page - 1, size); + return this.individualRepository.findAllIndividualsAutonomosByService(searchTerm, pageRequest); + } @Transactional public void saveExpertisesCompany(Company company, ProfessionalExpertise professionalExpertise) { diff --git a/src/main/java/br/edu/utfpr/servicebook/service/PaymentJobService.java b/src/main/java/br/edu/utfpr/servicebook/service/PaymentJobService.java new file mode 100644 index 00000000..0c07761e --- /dev/null +++ b/src/main/java/br/edu/utfpr/servicebook/service/PaymentJobService.java @@ -0,0 +1,32 @@ +package br.edu.utfpr.servicebook.service; + +import br.edu.utfpr.servicebook.model.entity.JobRequest; +import br.edu.utfpr.servicebook.model.entity.PaymentJobRequest; +import br.edu.utfpr.servicebook.model.repository.PaymentJobRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Optional; + +@Service +public class PaymentJobService { + @Autowired + private PaymentJobRepository paymentJobRepository; + + public void save(PaymentJobRequest entity) { + paymentJobRepository.save(entity); + } + + public List findAll() { + return this.paymentJobRepository.findAll(); + } + + public Optional findById(Long id) { + return this.paymentJobRepository.findById(id); + } + + public Optional findByJobRequest(JobRequest id) { + return this.paymentJobRepository.findByJobRequest(id); + } +} diff --git a/src/main/java/br/edu/utfpr/servicebook/service/PaymentService.java b/src/main/java/br/edu/utfpr/servicebook/service/PaymentService.java new file mode 100644 index 00000000..47d109ae --- /dev/null +++ b/src/main/java/br/edu/utfpr/servicebook/service/PaymentService.java @@ -0,0 +1,53 @@ +package br.edu.utfpr.servicebook.service; +import java.util.Map; +import java.util.Optional; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; +import org.springframework.http.*; +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestTemplate; + +import br.edu.utfpr.servicebook.model.entity.Payment; +import br.edu.utfpr.servicebook.model.repository.PaymentRepository; + + +@Service +public class PaymentService { + + private final Environment environment; + + @Autowired + private PaymentRepository paymentRepository; + + @Autowired + public PaymentService(Environment environment){ + this.environment = environment; + } + + public ResponseEntity pay(Map paymentData){ + RestTemplate restTemplate = new RestTemplate(); + String apiUrl = "https://api.mercadopago.com/v1/payments"; + + try { + String accessToken = environment.getProperty("MP_ACCESS_TOKEN"); + + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + headers.setBearerAuth(accessToken); + + HttpEntity> requestEntity = new HttpEntity<>(paymentData, headers); + + ResponseEntity response = restTemplate.exchange(apiUrl, HttpMethod.POST, requestEntity, Object.class); + return response; + + } catch (Exception e) { + throw new RuntimeException("Algo deu errado! Tente novamente."); + } + + } + + public Payment save(Payment entity){ return paymentRepository.save(entity); } + + public Optional find(Long payment){ return paymentRepository.findById(payment); } +} diff --git a/src/main/java/br/edu/utfpr/servicebook/service/PaymentVoucherService.java b/src/main/java/br/edu/utfpr/servicebook/service/PaymentVoucherService.java new file mode 100644 index 00000000..7faa9b95 --- /dev/null +++ b/src/main/java/br/edu/utfpr/servicebook/service/PaymentVoucherService.java @@ -0,0 +1,226 @@ +package br.edu.utfpr.servicebook.service; + +import br.edu.utfpr.servicebook.model.entity.PaymentVoucher; +import br.edu.utfpr.servicebook.model.repository.PaymentVoucherRepository; +import org.apache.batik.transcoder.TranscoderException; +import org.apache.fop.configuration.ConfigurationException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.w3c.dom.Document; + +import javax.xml.transform.TransformerException; +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.util.List; +import java.util.Optional; +import com.google.zxing.BarcodeFormat; +import com.google.zxing.WriterException; +import com.google.zxing.client.j2se.MatrixToImageWriter; +import com.google.zxing.common.BitMatrix; +import com.google.zxing.qrcode.QRCodeWriter; +import org.apache.batik.anim.dom.SAXSVGDocumentFactory; +import org.apache.batik.anim.dom.SVGDOMImplementation; +import org.apache.batik.svggen.SVGGraphics2D; +import org.apache.batik.svggen.SVGGraphics2DIOException; +import org.apache.batik.transcoder.TranscoderException; +import org.apache.batik.transcoder.TranscoderInput; +import org.apache.batik.transcoder.TranscoderOutput; +import org.apache.batik.util.XMLResourceDescriptor; +import org.apache.fop.activity.ContainerUtil; +import org.apache.fop.configuration.Configuration; +import org.apache.fop.configuration.ConfigurationException; +import org.apache.fop.configuration.DefaultConfigurationBuilder; +import org.apache.fop.svg.PDFTranscoder; +import org.springframework.stereotype.Service; +import org.springframework.util.ResourceUtils; +import org.w3c.dom.DOMImplementation; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.svg.SVGDocument; + +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; +import java.awt.*; +import java.io.*; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; +@Service +public class PaymentVoucherService { + + @Autowired + private PaymentVoucherRepository paymentVoucherRepository; + + public void save(PaymentVoucher entity) { + paymentVoucherRepository.save(entity); + } + + public List findAll() { + return this.paymentVoucherRepository.findAll(); + } + + public Optional findById(Long id) { + return this.paymentVoucherRepository.findById(id); + } + + /** + * Recebe a URL do template em SVG e gera o certificado em PDF, com as alterações devidas, retornando + * o File do PDF armazenado no diretório temporário local. + * @param svgCertificateTemplate + * @param name + * @param year + * @return + * @throws TranscoderException + * @throws IOException + * @throws ConfigurationException + * @throws TransformerException + */ + public File generateCertificate(String svgCertificateTemplate, String voucher, String service, String date, String date_due, + String name_client, String document_client, String fone_client, String mail_client, + String name_professional, String document_professional,String mail_professional, + String fone_professional, String endereco_pro, String payment_type, String payment_value, String qrCode) throws TranscoderException, IOException, ConfigurationException, TransformerException { + + //busca o template de certificado em SVG na nuvem + URL url = new URL(svgCertificateTemplate); + + //realiza a customização + Document doc = updateCertificate(url.openStream(), voucher, service,date, date_due,name_client,document_client,fone_client,mail_client,name_professional, document_professional, + mail_professional, fone_professional, endereco_pro, payment_type, payment_value, qrCode); + + //persiste as alterções em um SVG temporário + File fileSVG = convertDocumentToFile(doc); + + File filePDF = convertSVGToPDF(fileSVG); + + return filePDF; + } + + /** + * Recebe o SVG de certificado e realiza as edições de texto no DOM + * @param svgInputStream + * @return + * @throws IOException + */ + private Document updateCertificate(InputStream svgInputStream, String voucher, String service, String date, String date_due, + String name_client, String document_client, String fone_client, String mail_client, + String name_professional, String document_professional,String mail_professional, + String fone_professional, String endereco_pro, String payment_type, String payment_value, String qrCodeBase64) throws IOException { + String parser = XMLResourceDescriptor.getXMLParserClassName(); + SAXSVGDocumentFactory f = new SAXSVGDocumentFactory(parser); + + Document doc = f.createDocument(null, svgInputStream); + Element numberVoucher = doc.getElementById("number-voucher"); + numberVoucher.setTextContent(voucher); + + Element nameService = doc.getElementById("service-name"); + nameService.setTextContent(service); + + Element datePurchase = doc.getElementById("date-service"); + datePurchase.setTextContent(date); + + Element dateDue = doc.getElementById("date-due"); + dateDue.setTextContent(date_due); + + Element nameClient = doc.getElementById("name-client"); + nameClient.setTextContent(name_client); + + Element documentClient = doc.getElementById("document-client"); + documentClient.setTextContent(document_client); + + Element foneClient = doc.getElementById("fone-client"); + foneClient.setTextContent(fone_client); + + Element emailClient = doc.getElementById("mail_client"); + emailClient.setTextContent(mail_client); + + Element nameProfessional = doc.getElementById("name_professional"); + nameProfessional.setTextContent(name_professional); + + Element documentProfessional = doc.getElementById("document-professional"); + documentProfessional.setTextContent(document_professional); + + Element emailProfessional = doc.getElementById("mail_professional"); + emailProfessional.setTextContent(mail_professional); + + Element foneProfessional = doc.getElementById("fone-professional"); + foneProfessional.setTextContent(fone_professional); + + Element endereco = doc.getElementById("endereco"); + endereco.setTextContent(endereco_pro); + + Element valor = doc.getElementById("valor"); + valor.setTextContent(payment_value); + + Element payment = doc.getElementById("payment"); + payment.setTextContent(payment_type); + + +// Element qrElement = doc.getElementById("image0"); +// qrElement.setAttribute("xlink:href", qrCodeBase64); + + return doc; + } + + /** + * Recebe um document DOM e realiza a transformação em um arquivo persistido temporáriamente + * @param doc + * @return + * @throws IOException + * @throws TransformerException + */ + private File convertDocumentToFile(Document doc) throws IOException, TransformerException { + Path pathSVG = Files.createTempFile("certificado", ".svg"); + File fileSVG = pathSVG.toFile(); + FileWriter fileWriter = new FileWriter(fileSVG); + + DOMSource source = new DOMSource(doc); + StreamResult result = new StreamResult(fileWriter); + + TransformerFactory transformerFactory = TransformerFactory.newInstance(); + Transformer transformer = transformerFactory.newTransformer(); + transformer.transform(source, result); + return fileSVG; + } + + /** + * Converte um SVG para PDF + * @param fileSVG + * @return + * @throws IOException + * @throws ConfigurationException + * @throws TranscoderException + */ + private File convertSVGToPDF(File fileSVG) throws IOException, ConfigurationException, TranscoderException { + + File filePDF = null; + + PDFTranscoder transcoder = new PDFTranscoder(); + + //carrega o arquivo de configuração + DefaultConfigurationBuilder cfgBuilder = new DefaultConfigurationBuilder(); + //File configFile = ResourceUtils.getFile("classpath:fop-config.xml"); + Configuration cfg = cfgBuilder.buildFromFile(ResourceUtils.getFile("classpath:fop-config.xml")); + ContainerUtil.configure(transcoder, cfg); + + //Faz a leitura do novo SVG + TranscoderInput transcoderInput = new TranscoderInput(new FileInputStream(fileSVG)); + + //define o diretório temporário e o prefixo e sufixo do arquivo + Path pathPDF = Files.createTempFile("certificado", ".pdf"); + filePDF = pathPDF.toFile(); + + //realiza a transformação de SVG para PDF e guarda na pasta temporária + OutputStream outputStream = new FileOutputStream(filePDF); + TranscoderOutput transcoderOutput = new TranscoderOutput(outputStream); + transcoder.transcode(transcoderInput, transcoderOutput); + outputStream.flush(); + outputStream.close(); + + + return filePDF; + } +} diff --git a/src/main/java/br/edu/utfpr/servicebook/service/ProfessionalServiceOfferingAdItemService.java b/src/main/java/br/edu/utfpr/servicebook/service/ProfessionalServiceOfferingAdItemService.java index f115142b..547c0701 100644 --- a/src/main/java/br/edu/utfpr/servicebook/service/ProfessionalServiceOfferingAdItemService.java +++ b/src/main/java/br/edu/utfpr/servicebook/service/ProfessionalServiceOfferingAdItemService.java @@ -1,7 +1,9 @@ package br.edu.utfpr.servicebook.service; +import br.edu.utfpr.servicebook.model.entity.ProfessionalServiceOffering; import br.edu.utfpr.servicebook.model.entity.ProfessionalServicePackageOffering; import br.edu.utfpr.servicebook.model.entity.ProfessionalServiceOfferingAdItem; +import br.edu.utfpr.servicebook.model.entity.User; import br.edu.utfpr.servicebook.model.repository.ProfessionalServiceOfferingAdItemRepository; import org.springframework.beans.factory.annotation.Autowired; @@ -16,4 +18,17 @@ public class ProfessionalServiceOfferingAdItemService { public List findAllByProfessionalServicePackageOffering(ProfessionalServicePackageOffering professionalServicePackageOffering){ return professionalServiceOfferingAdItemRepository.findAllByProfessionalServicePackageOffering(professionalServicePackageOffering); } + +// /** +// * Salva uma oferta de serviço de um profissional +// * @param professionalServiceOfferingAdItem +// */ + public ProfessionalServiceOfferingAdItem save(ProfessionalServiceOfferingAdItem professionalServiceOfferingAdItem){ + return this.professionalServiceOfferingAdItemRepository.save(professionalServiceOfferingAdItem); + } + + public List findAllByProfessionalServicePackageOfferingUser(User user){ + return professionalServiceOfferingAdItemRepository.findProfessionalServiceOfferingAdItemsWithRelatedEntities(user); + } + } diff --git a/src/main/java/br/edu/utfpr/servicebook/service/ProfessionalServiceOfferingService.java b/src/main/java/br/edu/utfpr/servicebook/service/ProfessionalServiceOfferingService.java index 59ca9a31..f6c3ef60 100644 --- a/src/main/java/br/edu/utfpr/servicebook/service/ProfessionalServiceOfferingService.java +++ b/src/main/java/br/edu/utfpr/servicebook/service/ProfessionalServiceOfferingService.java @@ -1,12 +1,11 @@ package br.edu.utfpr.servicebook.service; -import br.edu.utfpr.servicebook.model.entity.Expertise; -import br.edu.utfpr.servicebook.model.entity.ProfessionalServiceOffering; -import br.edu.utfpr.servicebook.model.entity.Service; -import br.edu.utfpr.servicebook.model.entity.User; +import br.edu.utfpr.servicebook.model.entity.*; import br.edu.utfpr.servicebook.model.repository.CategoryRepository; import br.edu.utfpr.servicebook.model.repository.ProfessionalServiceOfferingRepository; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; import org.springframework.data.jpa.repository.Query; import java.util.List; import java.util.Optional; @@ -50,6 +49,13 @@ public List findProfessionalServiceOfferingByUser(U return professionalServiceOfferingRepository.findProfessionalServiceOfferingByUser(user); } + public List findFirst3ProfessionalServiceOfferingByUserAndType(User user, Enum type){ + return professionalServiceOfferingRepository.findFirst3ByUserAndType(user, type); + } + + public List findProfessionalServiceOfferingByUserAndType(User user, Enum type){ + return professionalServiceOfferingRepository.findByUserAndType(user, type); + } /** * Busca todas as ofertas de serviços de um profissional * @param id @@ -68,6 +74,11 @@ public List findProfessionalServiceOfferingByServic return professionalServiceOfferingRepository.findProfessionalServiceOfferingByService(service); } + public Page findDistinctByTermIgnoreCaseWithPagination(String searchTerm, Integer page, Integer size){ + PageRequest pageRequest = PageRequest.of(page - 1, size); + return this.professionalServiceOfferingRepository.findDistinctByTermIgnoreCaseWithPagination(searchTerm, pageRequest); + } + /** * Busca todas os serviços de um profissional por serviço cadastrado pelo administrador. */ @@ -97,4 +108,31 @@ public List findProfessionalServiceOfferingByUserAn public Optional findProfessionalServiceOfferingByName(String name){ return professionalServiceOfferingRepository.findProfessionalServiceOfferingByName(name); } + + public Page findAllIndividualsByService(Service searchTerm, Integer page, Integer size){ + PageRequest pageRequest = PageRequest.of(page - 1, size); + return this.professionalServiceOfferingRepository.findAllIndividualsByService(searchTerm, pageRequest); + } + + + /** + * Busca o serviço pelo id. + * @param id + * @return + */ + public Optional findProfessionalServiceOfferingByName(Long id){ + return professionalServiceOfferingRepository.findProfessionalServiceOfferingById(id); + } + + public List findAllByProfessionalServicePackageOfferingUser(User professionalServicePackageOffering){ + return professionalServiceOfferingRepository.findProfessionalServiceOfferingAdItemsByUser(professionalServicePackageOffering); + } + + public List findAll(){ + return professionalServiceOfferingRepository.findDistinctProfessionalServiceOfferings(); + } + + public Optional findProfessionalServiceOfferingByExpertiseAAndUser(Long user, Long expertise){ + return professionalServiceOfferingRepository.findProfessionalServiceOfferingByExpertiseAAndUser(user, expertise); + } } diff --git a/src/main/java/br/edu/utfpr/servicebook/service/ProfessionalServicePackageOfferingService.java b/src/main/java/br/edu/utfpr/servicebook/service/ProfessionalServicePackageOfferingService.java index 2dd243c3..01b0a3fb 100644 --- a/src/main/java/br/edu/utfpr/servicebook/service/ProfessionalServicePackageOfferingService.java +++ b/src/main/java/br/edu/utfpr/servicebook/service/ProfessionalServicePackageOfferingService.java @@ -32,7 +32,27 @@ public List findAllByUserAndExpertise(User u /** * Busca os anúncios de pacote de serviços de um dado profissional. */ - public List findAllByUser(User user){ - return this.professionalServicePackageOfferingRepository.findAllByUser(user); + public List findAllByUserAndType(User user, Enum type){ + return this.professionalServicePackageOfferingRepository.findFirst3ByUserAndType(user, type); + } + + /** + * Salva uma oferta de serviço de um profissional + * @param professionalServicePackageOffering + */ + public void save(ProfessionalServicePackageOffering professionalServicePackageOffering){ + professionalServicePackageOfferingRepository.save(professionalServicePackageOffering); + } + + public ProfessionalServicePackageOffering findById(Long id) { + return professionalServicePackageOfferingRepository.findById(id).orElse(null); + } + + public List findByTypeAndUser(User user, Enum type) { + return professionalServicePackageOfferingRepository.findByUserAndType(user,type); + } + + public List findAllByCombinedAndItems(User user) { + return professionalServicePackageOfferingRepository.findAllByCombinedAndItems(user); } } diff --git a/src/main/java/br/edu/utfpr/servicebook/service/QuartzService.java b/src/main/java/br/edu/utfpr/servicebook/service/QuartzService.java index de9d2e74..e45e0ac9 100644 --- a/src/main/java/br/edu/utfpr/servicebook/service/QuartzService.java +++ b/src/main/java/br/edu/utfpr/servicebook/service/QuartzService.java @@ -213,4 +213,31 @@ public void deleteJobsAvailableToHide() { System.out.println(e.getMessage()); } } + + /** Envio de email para o cliente e profissional com o comprovante de pagamento*/ + public void sendEmailPaymentVoucher(String codePayment, Long client, Long professional, String service, String date, String voucher) { + try { + System.out.println("clientId---------------------"); + System.out.println(client); + JobDetail job = JobBuilder.newJob(SendEmailVoucher.class) + .withIdentity(SendEmailVoucher.class.getSimpleName(), GROUP).build(); + job.getJobDataMap().put(SendEmailVoucher.PAYMENT_KEY, codePayment); + job.getJobDataMap().put(String.valueOf((Long) SendEmailVoucher.CLIENT_ID), client); + job.getJobDataMap().put(String.valueOf(SendEmailVoucher.PROFESSIONAL_ID), professional); + job.getJobDataMap().put(SendEmailVoucher.SERVICE_KEY, service); + job.getJobDataMap().put(SendEmailVoucher.DATE_KEY, date); + job.getJobDataMap().put(SendEmailVoucher.VOUCHER_KEY, voucher); + + Trigger trigger = getTrigger(SendEmailWithVerificationCodeJob.class.getSimpleName(), GROUP); + + scheduler.scheduleJob(job, trigger); + + if (!scheduler.isStarted()) { + scheduler.start(); + } + + }catch (SchedulerException e){ + System.out.println(e.getMessage()); + } + } } diff --git a/src/main/java/br/edu/utfpr/servicebook/service/ServiceService.java b/src/main/java/br/edu/utfpr/servicebook/service/ServiceService.java index 09450fe8..ba373f91 100644 --- a/src/main/java/br/edu/utfpr/servicebook/service/ServiceService.java +++ b/src/main/java/br/edu/utfpr/servicebook/service/ServiceService.java @@ -6,6 +6,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 54d5d60b..bb0ebd8f 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -94,3 +94,7 @@ perspective.api.key=${PERSPECTIVE_API_KEY} # Profile: Active. #******************************** spring.profiles.active=dev +#******************************** +# Outros +#******************************** +svg.certificate.template:https://res.cloudinary.com/dgueb0wir/image/upload/v1713740121/servicebook/voucher/voucher-copia_lyldoc.svg \ No newline at end of file diff --git a/src/main/resources/data.sql b/src/main/resources/data.sql index 82ffd9c3..569c1d86 100644 --- a/src/main/resources/data.sql +++ b/src/main/resources/data.sql @@ -88,9 +88,19 @@ INSERT INTO services (name, description, allow_scheduling, path_icon, expertise_ VALUES ('Balanceamento', 'Balanceamento das rodas', false, 'https://res.cloudinary.com/dgueb0wir/image/upload/v1689176876/servicebook/expertises/mecanico_quczum.svg', 4), ('Troca de óleo', 'Troca do óleo do motor', false, 'https://res.cloudinary.com/dgueb0wir/image/upload/v1689176876/servicebook/expertises/mecanico_quczum.svg', 4); -INSERT INTO professional_service_offerings (name, description, service_id, user_id) -VALUES ('Balanceamento com máquina importada', 'O balanceamento com 100% de garantia', 1, 2), - (null, null, 2, 2); +-- INSERT INTO professional_service_offerings (name, description, price, unit, duration, service_id, user_id, type, id) +-- VALUES ('Balanceamento com máquina importada', 'O balanceamento com 100% de garantia', 19000, 'Hora', '2 Horas', 1, 2, 'INDIVIDUAL', 1), +-- ('Balanceamento com máquina importada1', 'O balanceamento com 100% de garantia', 219000, 'Hora', '2 Horas', 1, 2, 'COMBINED_PACKAGE', 2); +-- ('Balanceamento com máquina importada2', 'O balanceamento com 100% de garantia', 19000, 'Hora', '2 Horas', 1, 2, 'INDIVIDUAL', 3), +-- ('Balanceamento com máquina importada3', 'O balanceamento com 100% de garantia', 19000, 'Hora', '2 Horas', 1, 2, 'INDIVIDUAL', 4); +-- (null, null, 2, 2); + +-- INSERT INTO professional_service_package_offering (name, description, price, unit, duration, service_id, user_id, type, amount,id) +-- VALUES ('Balanceamento com máquina importada', 'O balanceamento com 100% de garantia', 19000, 'Hora', '2 Horas', 1, 2, 'SIMPLE_PACKAGE', 2, 1), +-- ('Balanceamento com máquina importada', 'O balanceamento com 100% de garantia', 19000, 'Hora', '2 Horas', 1, 2, 'COMBINED_PACKAGE', 2, 2); +-- ('Balanceamento com máquina importada', 'O balanceamento com 100% de garantia', 19000, 'Hora', '2 Horas', 1, 2, 'SIMPLE_PACKAGE', 2, 3), +-- ('Balanceamento com máquina importada', 'O balanceamento com 100% de garantia', 19000, 'Hora', '2 Horas', 1, 2, 'SIMPLE_PACKAGE', 2, 4), +-- ('Balanceamento com máquina importada', 'O balanceamento com 100% de garantia', 19000, 'Hora', '2 Horas', 1, 2, 'SIMPLE_PACKAGE', 2, 5); INSERT INTO companies (cnpj, id) VALUES ('98.988.640/0001-91', 7); @@ -128,19 +138,19 @@ VALUES ('false', '2021-01-01', '2021-01-01', 'Preciso de um Encanador 1!', 'true INSERT INTO job_contracted (comments, rating, job_request, professional, hired_date, todo_date) -VALUES ('Ótimo Encanador!', '5', '19', '5', '2021-04-01', '2021-08-26'), - ('Ótimo Eletricista!', '5', '10', '2', '2021-04-01', '2021-08-26'), - ('Ótimo Pintor!', '5', '16', '2', '2021-04-01', '2021-08-26'), - ('Bom Encanador!', '3', '5', '2', '2021-04-01', '2021-08-26'), - ('Bom Encanador!', '3', '8', '2', '2021-04-01', '2021-08-26'), - ('Bom Encanador!', '3', '9', '2', '2021-04-01', '2021-08-26'), - ('Péssimo Encanador!', '1', '6', '2', '2021-04-01', '2021-08-26'), - ('Bom Eletricista!', '3', '11', '2', '2021-04-01', '2021-08-26'), - ('Péssimo Eletricista!', '1', '12', '2', '2021-04-01', '2021-08-26'), - ('Bom Pintor!', '3', '15', '2', '2021-04-01','2021-08-26'), - ('Bom Pintor!', '3', '20', '2', '2021-04-01', '2021-08-26'), - ('Bom Pintor!', '3', '21', '2', '2021-04-01', '2021-08-26'), - ('Péssimo Pintor!', '1', '14', '2', '2021-04-01', '2021-08-26'); +VALUES ('Ótimo Encanador!', '5', '19', '5', '2024-04-01', '2024-08-26'), + ('Ótimo Eletricista!', '5', '10', '2', '2024-04-01', '2024-08-26'), + ('Ótimo Pintor!', '5', '16', '2', '2024-04-01', '2024-08-26'), + ('Bom Encanador!', '3', '5', '2', '2024-04-01', '2024-08-26'), + ('Bom Encanador!', '3', '8', '2', '2024-04-01', '2024-08-26'), + ('Bom Encanador!', '3', '9', '2', '2024-04-01', '2024-08-26'), + ('Péssimo Encanador!', '1', '6', '2', '2024-04-01', '2024-08-26'), + ('Bom Eletricista!', '3', '11', '2', '2024-04-01', '2024-08-26'), + ('Péssimo Eletricista!', '1', '12', '2', '2024-04-01', '2024-08-26'), + ('Bom Pintor!', '3', '15', '2', '2024-04-01','2024-08-26'), + ('Bom Pintor!', '3', '20', '2', '2024-04-01', '2024-08-26'), + ('Bom Pintor!', '3', '21', '2', '2024-04-01', '2024-08-26'), + ('Péssimo Pintor!', '1', '14', '2', '2024-04-01', '2024-08-26'); @@ -154,6 +164,25 @@ VALUES ('1', '2', 'false'), INSERT INTO follows (client_id, professional_id) -VALUES (4, 2) - - +VALUES (4, 2); + +-- DURAÇÃO DE SERVIÇOS +INSERT INTO duration_services (name) +VALUES ('Sem agendamento'), + ('30 minutos'), + ('1 hora'), + ('1 hora e meia'), + ('2 horas'), + ('3 horas'), + ('Um período do dia'), + ('O dia inteiro'); + +-- UNIDADE DE PREÇO +INSERT INTO price_units (name) +VALUES ('Hora'), + ('Metro quadrado'), + ('Unidade'); + + +INSERT INTO payments (id, payment_id, status) +VALUES (1, 1, 'approved') \ No newline at end of file diff --git a/src/main/resources/fop-config.xml b/src/main/resources/fop-config.xml new file mode 100644 index 00000000..28ef8b0c --- /dev/null +++ b/src/main/resources/fop-config.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/src/main/resources/images/voucher-copia.svg b/src/main/resources/images/voucher-copia.svg new file mode 100644 index 00000000..fda689fd --- /dev/null +++ b/src/main/resources/images/voucher-copia.svg @@ -0,0 +1,64 @@ + + + + +Detalhes da compra + + VOUCHER + numero + + Serviço: + nome servico + + Data Compra: + 02/04/2024 + + Data Vencimento: + 17/04/2024 + +Comprador(a): +Nome comprador + + Documento: +111.111.111-11 + + Telefone: +42999935496 + + Telefone: + 42999935496 + + Documento: +111.111.111-11 + + Vendedor(a): +Nome vendedor + +Email: +thryssai@gmail.com + + Email: +thryssai@gmail.com + +Endereço: +Jundiai , 241 - Guarapuava/PR + +Obeservações: + + + + + +Pagamento: + PIX + +Valor Pago: R$ +150,00 + + + + + + + + diff --git a/src/main/resources/images/voucher.svg b/src/main/resources/images/voucher.svg new file mode 100644 index 00000000..f3d4148d --- /dev/null +++ b/src/main/resources/images/voucher.svg @@ -0,0 +1,57 @@ + + + + +Detalhes da compra + + VOUCHER + numero + + Serviço: + nome servico + + Data Compra: + 02/04/2024 + +Comprador(a): + +Nome comprador +111.111.111-11 +111.111.111-11 +42999935496 +42999935496 +111.111.111-11 +Nome vendedor +Documento: +Telefone: +Telefone: +Documento: +Vendedor(a): +Email: +thryssai@gmail.com +thryssai@gmail.com +Endereço: +Jundiai , 241 - Guarapuava/PR +Obeservações: +Email: + +Data Vencimento: +17/04/2024 + + + + + + +Pagamento: +Valor Pago: R$ +150,00 +PIX + + + + + + + + diff --git a/src/main/resources/images/voucher_pagamento.svg b/src/main/resources/images/voucher_pagamento.svg new file mode 100644 index 00000000..034d9c3c --- /dev/null +++ b/src/main/resources/images/voucher_pagamento.svg @@ -0,0 +1,8 @@ + + + + CERTIFICADO + NOME + + ANO + \ No newline at end of file diff --git a/src/main/resources/static/fonts/Roboto-Black.ttf b/src/main/resources/static/fonts/Roboto-Black.ttf new file mode 100644 index 00000000..43a00e0d Binary files /dev/null and b/src/main/resources/static/fonts/Roboto-Black.ttf differ diff --git a/src/main/resources/static/fonts/Roboto-Bold.ttf b/src/main/resources/static/fonts/Roboto-Bold.ttf new file mode 100644 index 00000000..37424579 Binary files /dev/null and b/src/main/resources/static/fonts/Roboto-Bold.ttf differ diff --git a/src/main/resources/static/fonts/Roboto-Regular.ttf b/src/main/resources/static/fonts/Roboto-Regular.ttf new file mode 100644 index 00000000..3d6861b4 Binary files /dev/null and b/src/main/resources/static/fonts/Roboto-Regular.ttf differ diff --git a/src/main/webapp/WEB-INF/tags/my-ads-combined.tag b/src/main/webapp/WEB-INF/tags/my-ads-combined.tag new file mode 100644 index 00000000..587c258b --- /dev/null +++ b/src/main/webapp/WEB-INF/tags/my-ads-combined.tag @@ -0,0 +1,38 @@ +<%@tag description="Servicebook - Banner template" pageEncoding="UTF-8" %> +<%@attribute name="cities" type="java.util.List" %> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> +<%@ taglib prefix = "fmt" uri = "http://java.sun.com/jsp/jstl/fmt" %> + +<%@ attribute name="items" required="false" type="java.util.ArrayList"%> + + +
+ Serviços Combinados + ver mais navigate_next +
+ +
+

${service.professionalServiceOffering.service.expertise.name}

+
+
+ ${service.professionalServicePackageOffering.duration} +
+
+
+ +
+ +
+
+
+ ${service.professionalServicePackageOffering.description} +
+
+
+
+

+
+
+

${service.professionalServiceOffering.service.name}

+
+
diff --git a/src/main/webapp/WEB-INF/tags/my-ads-package.tag b/src/main/webapp/WEB-INF/tags/my-ads-package.tag new file mode 100644 index 00000000..64601b4a --- /dev/null +++ b/src/main/webapp/WEB-INF/tags/my-ads-package.tag @@ -0,0 +1,44 @@ +<%@tag description="Servicebook - Banner template" pageEncoding="UTF-8" %> +<%@attribute name="cities" type="java.util.List" %> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> +<%@ taglib prefix = "fmt" uri = "http://java.sun.com/jsp/jstl/fmt" %> + +<%@ attribute name="itemsService" required="false" type="java.util.ArrayList" %> + + +
+ Pacote de Serviços + ver mais navigate_next +
+ +
+

${service.service.expertise.name}

+ +
+
+ ${service.duration} +
+
+
+ +
+ +
+
+ +
+

${service.description}

+

Pacote com ${service.amount}

+
+
+ +
+
+

+
+
+

${service.service.name}

+
+
diff --git a/src/main/webapp/WEB-INF/tags/navbar-professional.tag b/src/main/webapp/WEB-INF/tags/navbar-professional.tag index c58cc98c..288902ab 100644 --- a/src/main/webapp/WEB-INF/tags/navbar-professional.tag +++ b/src/main/webapp/WEB-INF/tags/navbar-professional.tag @@ -63,6 +63,7 @@ ${userInfo.name}
  • +
  • Meus Anúncios
  • Minha Conta
  • Meu Perfil
  • diff --git a/src/main/webapp/WEB-INF/tags/search-bar.tag b/src/main/webapp/WEB-INF/tags/search-bar.tag index dde28e28..73c02df0 100644 --- a/src/main/webapp/WEB-INF/tags/search-bar.tag +++ b/src/main/webapp/WEB-INF/tags/search-bar.tag @@ -1,33 +1,91 @@ <%@tag description="Servicebook - Search bar template" pageEncoding="UTF-8" %> +<%@attribute name="items" type="java.util.ArrayList" %> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + +
    -
    + + +
    +
    +
    +

    O QUE VOCÊ PRECISA?

    +
    Nos informe de qual serviço você precisa e escolha o melhor profissional!
    +
    +
    + +
    +
    +
    + ${msg} +
    +
    +
    +
    + +
    +
    +
    + + +
    +
    + + + +
    + +
    + + + + +
    +
    -
    -

    O QUE VOCÊ PRECISA?

    -
    +
    + +
    +
    +
    +
    +
    + + +
    +
    +
    +

    O QUE VOCÊ PRECISA?

    +
    Crie um anúncio da sua solicitação para facilitar a comunicação com os profissionais.
    +
    Você descreve apenas uma vez e compartilha com os profissionais.
    + BUSCA DESCRITIVA +
    -
    -
    -
    - -
    -
    -
    -
    - -
    -
    -
    -
    \ No newline at end of file +
    + + +
    + diff --git a/src/main/webapp/WEB-INF/tags/template.tag b/src/main/webapp/WEB-INF/tags/template.tag index dd89cfcb..5798d36f 100644 --- a/src/main/webapp/WEB-INF/tags/template.tag +++ b/src/main/webapp/WEB-INF/tags/template.tag @@ -12,13 +12,28 @@ + + + + + + + + + + + + ${title} + + - + + + @@ -131,12 +146,15 @@ src="https://code.jquery.com/jquery-3.7.0.min.js" integrity="sha256-2Pmvv0kuTBOenSvLm6bvfBSSHrUJ+3A7x6P5Ebd07/g=" crossorigin="anonymous"> + + + - diff --git a/src/main/webapp/WEB-INF/view/client/details-request.jsp b/src/main/webapp/WEB-INF/view/client/details-request.jsp index 9bd4c152..9eddd236 100644 --- a/src/main/webapp/WEB-INF/view/client/details-request.jsp +++ b/src/main/webapp/WEB-INF/view/client/details-request.jsp @@ -7,6 +7,15 @@ + + + @@ -108,6 +117,25 @@ > + + + +
    +
    + + +
    +
    @@ -234,5 +262,4 @@ } }); }); - - + \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/view/client/job-request/wizard-step-08.jsp b/src/main/webapp/WEB-INF/view/client/job-request/wizard-step-08.jsp index d2b305ae..53fc818c 100644 --- a/src/main/webapp/WEB-INF/view/client/job-request/wizard-step-08.jsp +++ b/src/main/webapp/WEB-INF/view/client/job-request/wizard-step-08.jsp @@ -14,16 +14,83 @@ +
    -
    -

    Olá João, recebemos a sua solicitação de serviço!

    -

    Fique atento, logo você começará a receber os contatos dos profissionais interessados em realizar o serviço no prazo especificado!

    -
    -
    - Acompanhe a sua solicitação +
    +

    Estes ${professionalsAmount} profissionais tem a especialidade que procura!

    +
    Para ter acesso a lista completa de profissionais deste especialidade ou melhor, para receber o contato de apenas profissionais interessados e disponíveis para a data especificada, podendo você verificar a reputação dos mesmos e experiência, solicitar orçamento e por fim, avaliar o serviço prestado.
    +
    +
    +
    +
    +
    + + +
    +
    +
    +
    + + + Foto de perfil + + + Sem foto de perfil + + +
    +
    +
    ${professional.name}
    +
    +
    +
    + +
    ${expertise.name}
    +
    +
    +
    + +
    +
    +
    +
    + +
    +
    +
    +
    + sentiment_dissatisfied +

    + Nenhum profissional encontrado! +

    +
    +
    +
    +
    +
    +
    +
    +
    + +
    +
    +

    LOGIN PARA EFETIVAR O SEU PEDIDO E RECEBER OS CONTATOS DOS PROFISSIONAIS!

    + Entrar +
    + +
    + +
    +

    VOCÊ AINDA NÃO TEM UMA CONTA?

    + Cadastrar-se +
    +
    +
    diff --git a/src/main/webapp/WEB-INF/view/professional/ads/my-ads-combineds.jsp b/src/main/webapp/WEB-INF/view/professional/ads/my-ads-combineds.jsp new file mode 100644 index 00000000..65b12cef --- /dev/null +++ b/src/main/webapp/WEB-INF/view/professional/ads/my-ads-combineds.jsp @@ -0,0 +1,99 @@ +<%@page contentType="text/html" pageEncoding="UTF-8" %> +<%@taglib prefix="t" tagdir="/WEB-INF/tags" %> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> +<%@ taglib prefix = "fmt" uri = "http://java.sun.com/jsp/jstl/fmt" %> + + + + + + + + + +
    +
    +
    +
    + + + + +
    +

    Meus Anúncios

    +
    +
    +

    Serviços Combinados.

    +
    + +
    + +
    + + +
    +

    ${service.service.expertise.name}

    +
    +
    + ${service.duration} +
    +
    +
    + +
    + +
    +
    +
    + ${service.description} +
    +
    +
    +
    +

    +
    +
    +

    ${service.service.name}

    +
    +
    + +
    +
    +
    +
    + +
    +
    + + \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/view/professional/ads/my-ads-individuals.jsp b/src/main/webapp/WEB-INF/view/professional/ads/my-ads-individuals.jsp new file mode 100644 index 00000000..4381d56f --- /dev/null +++ b/src/main/webapp/WEB-INF/view/professional/ads/my-ads-individuals.jsp @@ -0,0 +1,99 @@ +<%@page contentType="text/html" pageEncoding="UTF-8" %> +<%@taglib prefix="t" tagdir="/WEB-INF/tags" %> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> +<%@ taglib prefix = "fmt" uri = "http://java.sun.com/jsp/jstl/fmt" %> + + + + + + + + + +
    +
    +
    +
    + + + + +
    +

    Meus Anúncios

    +
    +
    +

    Serviços Individuais.

    +
    + +
    + +
    + + +
    +

    ${service.service.expertise.name}

    +
    +
    + ${service.duration} +
    +
    +
    + +
    + +
    +
    +
    + ${service.description} +
    +
    +
    +
    +

    +
    +
    +

    ${service.service.name}

    +
    +
    + +
    +
    +
    +
    + +
    +
    + + \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/view/professional/ads/my-ads-packages.jsp b/src/main/webapp/WEB-INF/view/professional/ads/my-ads-packages.jsp new file mode 100644 index 00000000..6456397b --- /dev/null +++ b/src/main/webapp/WEB-INF/view/professional/ads/my-ads-packages.jsp @@ -0,0 +1,101 @@ +<%@page contentType="text/html" pageEncoding="UTF-8" %> +<%@taglib prefix="t" tagdir="/WEB-INF/tags" %> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> +<%@ taglib prefix = "fmt" uri = "http://java.sun.com/jsp/jstl/fmt" %> + + + + + + + + + +
    +
    +
    +
    + + + + +
    +

    Meus Anúncios

    +
    +
    +

    Pacotes de Serviços.

    +
    + +
    + +
    + + +
    +

    ${service.service.expertise.name}

    +
    +
    + ${service.duration} +
    +
    +
    + +
    + +
    +
    +
    +

    ${service.description}

    +

    Pacote com ${service.amount}

    +
    +
    +
    +
    +

    +
    +
    +

    ${service.service.name}

    + +
    +
    + +
    +
    +
    +
    + +
    +
    + + \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/view/professional/my-ads-register-combined.jsp b/src/main/webapp/WEB-INF/view/professional/my-ads-register-combined.jsp new file mode 100644 index 00000000..1b30e31a --- /dev/null +++ b/src/main/webapp/WEB-INF/view/professional/my-ads-register-combined.jsp @@ -0,0 +1,96 @@ +<%@page contentType="text/html" pageEncoding="UTF-8" %> +<%@taglib prefix="t" tagdir="/WEB-INF/tags" %> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + +
    +
    + +
    +
    +

    SERVIÇO

    +
    +
    +
    +

    Qual a especialidade?

    + +
    +
    +

    Quais os serviços?

    + +
    + +
    +

    Titulo

    + + + + +

    + +

    + +
    +
    +

    PREÇO E AGENDAMENTO

    +
    +
    +
    +

    Qual a unidade de preço do serviço?

    + +
    + +
    +

    Quanto você cobra por este serviço?

    + + + +
    + +
    +

    Qual a Duração do serviço?

    + +
    + +
    +
    + Cancelar + +
    + +
    +
    + \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/view/professional/my-ads-register-package.jsp b/src/main/webapp/WEB-INF/view/professional/my-ads-register-package.jsp new file mode 100644 index 00000000..7ce4d5a6 --- /dev/null +++ b/src/main/webapp/WEB-INF/view/professional/my-ads-register-package.jsp @@ -0,0 +1,100 @@ +<%@page contentType="text/html" pageEncoding="UTF-8" %> +<%@taglib prefix="t" tagdir="/WEB-INF/tags" %> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + +
    +
    + +
    +
    +

    SERVIÇO

    +
    +
    +
    +

    Qual a especialidade?

    + +
    + +
    +

    Qual o serviço?

    + +
    + +
    +

    Titulo

    + + +

    + +

    +
    +
    +

    PREÇO E AGENDAMENTO

    +
    +
    +
    +

    Qual a unidade de preço do serviço?

    + +
    + +
    +

    Quanto você cobra por este serviço?

    + + + +
    + +
    +

    Qual a quantidade para o pacote?

    + +
    + +
    +

    Qual a Duração do serviço?

    + +
    + +
    +
    + Cancelar + +
    + +
    +
    + + \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/view/professional/my-ads-register.jsp b/src/main/webapp/WEB-INF/view/professional/my-ads-register.jsp new file mode 100644 index 00000000..378b167f --- /dev/null +++ b/src/main/webapp/WEB-INF/view/professional/my-ads-register.jsp @@ -0,0 +1,170 @@ +<%@page contentType="text/html" pageEncoding="UTF-8" %> +<%@taglib prefix="t" tagdir="/WEB-INF/tags" %> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + + + + + +
    +
    +
    +
    + + + +
    +

    Anunciar Serviços

    +
    +
    +

    + Serviço Individual, você adiciona um anúncio simples, podendo alterar o titulo do anúncio caso ache necessário. +

    +

    + Combinação de Serviços, você pode adicionar mais de um serviço no anúncio, desde que todos estejam ativados para anúncio, + como por exemplo balanceamento + geometria . +

    +

    + Pacote de Serviços, você pode adicionar uma quantidade do mesmo produto, como por exemplo 5 sessões de massagens . +

    +
    + +
    +
    +

    TIPO DE ANÚNCIO

    +
    +
    +
    +

    Qual o tipo do serviço?

    + +
    + + + +
    +
    +

    SERVIÇO

    +
    +
    +
    +
    + +
    +
    +

    Qual a especialidade?

    + +
    + +
    +

    Qual o serviço?

    + +
    + +
    +

    Titulo

    + + +

    + +

    +
    +
    +

    PREÇO E AGENDAMENTO

    +
    +
    +
    +

    Qual a unidade de preço do serviço?

    + +
    + +
    +

    Quanto você cobra por este serviço?

    + + +
    + +
    +

    Qual a Duração do serviço?

    + +
    + +
    +
    + Cancelar + +
    + +
    +
    + +
    +
    +
    +
    +
    +
    + + \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/view/professional/my-ads.jsp b/src/main/webapp/WEB-INF/view/professional/my-ads.jsp new file mode 100644 index 00000000..774f9beb --- /dev/null +++ b/src/main/webapp/WEB-INF/view/professional/my-ads.jsp @@ -0,0 +1,136 @@ +<%@page contentType="text/html" pageEncoding="UTF-8" %> +<%@taglib prefix="t" tagdir="/WEB-INF/tags" %> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> +<%@ taglib prefix = "fmt" uri = "http://java.sun.com/jsp/jstl/fmt" %> + + + + + + + + + +
    +
    +
    +
    + + + + +
    +

    Meus Anúncios

    +
    +
    +

    Adicione anúncios dos serviços que você oferece dentro do Servicebook.

    +

    Se ativado o agendamento, o cliente possuira acesso a sua agenda, podendo visualizar os dias e horários + disponíveis. Além disso, você pode adicioanar o preço e duração dos seus serviços, dessa forma + permitindo que clientes adquiram seus serviços de forma rápida.

    +
    + + + + +
    + + +
    Serviços Individuais
    + +
    + + + +
    + Serviços Individuais + ver mais navigate_next +
    + + +
    +

    ${service.service.expertise.name}

    +
    +
    + ${service.duration} +
    +
    +
    + +
    + +
    +
    + +
    + ${service.description} +
    +
    +
    +
    +

    +
    +
    +

    ${service.service.name}

    +
    +
    + +
    + +
    + +
    Serviços Combinados
    + +
    + + + + +
    + +
    + +
    Pacotes de Serviços
    + +
    + + + + +
    + +
    +
    +
    +
    + +
    +
    + + \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/view/visitor/index.jsp b/src/main/webapp/WEB-INF/view/visitor/index.jsp index 3ee4fcb6..ef5c70cc 100644 --- a/src/main/webapp/WEB-INF/view/visitor/index.jsp +++ b/src/main/webapp/WEB-INF/view/visitor/index.jsp @@ -5,14 +5,13 @@ -
    - +
    @@ -74,3 +73,10 @@
    + + \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/view/visitor/search-results.jsp b/src/main/webapp/WEB-INF/view/visitor/search-results.jsp index d90d7530..9be5a209 100644 --- a/src/main/webapp/WEB-INF/view/visitor/search-results.jsp +++ b/src/main/webapp/WEB-INF/view/visitor/search-results.jsp @@ -1,6 +1,7 @@ <%@page contentType="text/html" pageEncoding="UTF-8" %> <%@taglib prefix="t" tagdir="/WEB-INF/tags" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> +<%@ taglib prefix = "fmt" uri = "http://java.sun.com/jsp/jstl/fmt" %> @@ -10,45 +11,60 @@ - - - +
    + + +
    +

    Foto de especialidade + ${dto_expertise.name} +

    + +

    ${service}

    +
    +
    +
    + PROFISSIONAIS +
    +
    - - -
    -
    -
    + + +
    +
    +
    + ${professional.service.expertise.name} +
    +
    - - Foto de perfil + + Foto de perfil Sem foto de perfil -
    -
    -
    ${professional.name}
    -
    -
    -
    - -
    ${expertise.name}
    -
    +
    +
    ${professional.user.name}
    + ${professional.description} +
    +
    -
    - Ver perfil +
    +

    + +
    @@ -84,8 +100,15 @@ + diff --git a/src/main/webapp/assets/libraries/select2/css/select2.min.css b/src/main/webapp/assets/libraries/select2/css/select2.min.css new file mode 100644 index 00000000..f00f1547 --- /dev/null +++ b/src/main/webapp/assets/libraries/select2/css/select2.min.css @@ -0,0 +1 @@ +.select2-container{box-sizing:border-box;display:inline-block;margin:0;position:relative;vertical-align:middle}.select2-container .select2-selection--single{box-sizing:border-box;cursor:pointer;display:block;height:28px;user-select:none;-webkit-user-select:none}.select2-container .select2-selection--single .select2-selection__rendered{display:block;padding-left:8px;padding-right:20px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.select2-container .select2-selection--single .select2-selection__clear{background-color:transparent;border:none;font-size:1em}.select2-container[dir="rtl"] .select2-selection--single .select2-selection__rendered{padding-right:8px;padding-left:20px}.select2-container .select2-selection--multiple{box-sizing:border-box;cursor:pointer;display:block;min-height:32px;user-select:none;-webkit-user-select:none}.select2-container .select2-selection--multiple .select2-selection__rendered{display:inline;list-style:none;padding:0}.select2-container .select2-selection--multiple .select2-selection__clear{background-color:transparent;border:none;font-size:1em}.select2-container .select2-search--inline .select2-search__field{box-sizing:border-box;border:none;font-size:100%;margin-top:5px;margin-left:5px;padding:0;max-width:100%;resize:none;height:18px;vertical-align:bottom;font-family:sans-serif;overflow:hidden;word-break:keep-all}.select2-container .select2-search--inline .select2-search__field::-webkit-search-cancel-button{-webkit-appearance:none}.select2-dropdown{background-color:white;border:1px solid #aaa;border-radius:4px;box-sizing:border-box;display:block;position:absolute;left:-100000px;width:100%;z-index:1051}.select2-results{display:block}.select2-results__options{list-style:none;margin:0;padding:0}.select2-results__option{padding:6px;user-select:none;-webkit-user-select:none}.select2-results__option--selectable{cursor:pointer}.select2-container--open .select2-dropdown{left:0}.select2-container--open .select2-dropdown--above{border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0}.select2-container--open .select2-dropdown--below{border-top:none;border-top-left-radius:0;border-top-right-radius:0}.select2-search--dropdown{display:block;padding:4px}.select2-search--dropdown .select2-search__field{padding:4px;width:100%;box-sizing:border-box}.select2-search--dropdown .select2-search__field::-webkit-search-cancel-button{-webkit-appearance:none}.select2-search--dropdown.select2-search--hide{display:none}.select2-close-mask{border:0;margin:0;padding:0;display:block;position:fixed;left:0;top:0;min-height:100%;min-width:100%;height:auto;width:auto;opacity:0;z-index:99;background-color:#fff;filter:alpha(opacity=0)}.select2-hidden-accessible{border:0 !important;clip:rect(0 0 0 0) !important;-webkit-clip-path:inset(50%) !important;clip-path:inset(50%) !important;height:1px !important;overflow:hidden !important;padding:0 !important;position:absolute !important;width:1px !important;white-space:nowrap !important}.select2-container--default .select2-selection--single{background-color:#fff;border:1px solid #aaa;border-radius:4px}.select2-container--default .select2-selection--single .select2-selection__rendered{color:#444;line-height:28px}.select2-container--default .select2-selection--single .select2-selection__clear{cursor:pointer;float:right;font-weight:bold;height:26px;margin-right:20px;padding-right:0px}.select2-container--default .select2-selection--single .select2-selection__placeholder{color:#999}.select2-container--default .select2-selection--single .select2-selection__arrow{height:26px;position:absolute;top:1px;right:1px;width:20px}.select2-container--default .select2-selection--single .select2-selection__arrow b{border-color:#888 transparent transparent transparent;border-style:solid;border-width:5px 4px 0 4px;height:0;left:50%;margin-left:-4px;margin-top:-2px;position:absolute;top:50%;width:0}.select2-container--default[dir="rtl"] .select2-selection--single .select2-selection__clear{float:left}.select2-container--default[dir="rtl"] .select2-selection--single .select2-selection__arrow{left:1px;right:auto}.select2-container--default.select2-container--disabled .select2-selection--single{background-color:#eee;cursor:default}.select2-container--default.select2-container--disabled .select2-selection--single .select2-selection__clear{display:none}.select2-container--default.select2-container--open .select2-selection--single .select2-selection__arrow b{border-color:transparent transparent #888 transparent;border-width:0 4px 5px 4px}.select2-container--default .select2-selection--multiple{background-color:white;border:1px solid #aaa;border-radius:4px;cursor:text;padding-bottom:5px;padding-right:5px;position:relative}.select2-container--default .select2-selection--multiple.select2-selection--clearable{padding-right:25px}.select2-container--default .select2-selection--multiple .select2-selection__clear{cursor:pointer;font-weight:bold;height:20px;margin-right:10px;margin-top:5px;position:absolute;right:0;padding:1px}.select2-container--default .select2-selection--multiple .select2-selection__choice{background-color:#e4e4e4;border:1px solid #aaa;border-radius:4px;box-sizing:border-box;display:inline-block;margin-left:5px;margin-top:5px;padding:0;padding-left:20px;position:relative;max-width:100%;overflow:hidden;text-overflow:ellipsis;vertical-align:bottom;white-space:nowrap}.select2-container--default .select2-selection--multiple .select2-selection__choice__display{cursor:default;padding-left:2px;padding-right:5px}.select2-container--default .select2-selection--multiple .select2-selection__choice__remove{background-color:transparent;border:none;border-right:1px solid #aaa;border-top-left-radius:4px;border-bottom-left-radius:4px;color:#999;cursor:pointer;font-size:1em;font-weight:bold;padding:0 4px;position:absolute;left:0;top:0}.select2-container--default .select2-selection--multiple .select2-selection__choice__remove:hover,.select2-container--default .select2-selection--multiple .select2-selection__choice__remove:focus{background-color:#f1f1f1;color:#333;outline:none}.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice{margin-left:5px;margin-right:auto}.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice__display{padding-left:5px;padding-right:2px}.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice__remove{border-left:1px solid #aaa;border-right:none;border-top-left-radius:0;border-bottom-left-radius:0;border-top-right-radius:4px;border-bottom-right-radius:4px}.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__clear{float:left;margin-left:10px;margin-right:auto}.select2-container--default.select2-container--focus .select2-selection--multiple{border:solid black 1px;outline:0}.select2-container--default.select2-container--disabled .select2-selection--multiple{background-color:#eee;cursor:default}.select2-container--default.select2-container--disabled .select2-selection__choice__remove{display:none}.select2-container--default.select2-container--open.select2-container--above .select2-selection--single,.select2-container--default.select2-container--open.select2-container--above .select2-selection--multiple{border-top-left-radius:0;border-top-right-radius:0}.select2-container--default.select2-container--open.select2-container--below .select2-selection--single,.select2-container--default.select2-container--open.select2-container--below .select2-selection--multiple{border-bottom-left-radius:0;border-bottom-right-radius:0}.select2-container--default .select2-search--dropdown .select2-search__field{border:1px solid #aaa}.select2-container--default .select2-search--inline .select2-search__field{background:transparent;border:none;outline:0;box-shadow:none;-webkit-appearance:textfield}.select2-container--default .select2-results>.select2-results__options{max-height:200px;overflow-y:auto}.select2-container--default .select2-results__option .select2-results__option{padding-left:1em}.select2-container--default .select2-results__option .select2-results__option .select2-results__group{padding-left:0}.select2-container--default .select2-results__option .select2-results__option .select2-results__option{margin-left:-1em;padding-left:2em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-2em;padding-left:3em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-3em;padding-left:4em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-4em;padding-left:5em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-5em;padding-left:6em}.select2-container--default .select2-results__option--group{padding:0}.select2-container--default .select2-results__option--disabled{color:#999}.select2-container--default .select2-results__option--selected{background-color:#ddd}.select2-container--default .select2-results__option--highlighted.select2-results__option--selectable{background-color:#5897fb;color:white}.select2-container--default .select2-results__group{cursor:default;display:block;padding:6px}.select2-container--classic .select2-selection--single{background-color:#f7f7f7;border:1px solid #aaa;border-radius:4px;outline:0;background-image:-webkit-linear-gradient(top, #fff 50%, #eee 100%);background-image:-o-linear-gradient(top, #fff 50%, #eee 100%);background-image:linear-gradient(to bottom, #fff 50%, #eee 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFFFF', endColorstr='#FFEEEEEE', GradientType=0)}.select2-container--classic .select2-selection--single:focus{border:1px solid #5897fb}.select2-container--classic .select2-selection--single .select2-selection__rendered{color:#444;line-height:28px}.select2-container--classic .select2-selection--single .select2-selection__clear{cursor:pointer;float:right;font-weight:bold;height:26px;margin-right:20px}.select2-container--classic .select2-selection--single .select2-selection__placeholder{color:#999}.select2-container--classic .select2-selection--single .select2-selection__arrow{background-color:#ddd;border:none;border-left:1px solid #aaa;border-top-right-radius:4px;border-bottom-right-radius:4px;height:26px;position:absolute;top:1px;right:1px;width:20px;background-image:-webkit-linear-gradient(top, #eee 50%, #ccc 100%);background-image:-o-linear-gradient(top, #eee 50%, #ccc 100%);background-image:linear-gradient(to bottom, #eee 50%, #ccc 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFEEEEEE', endColorstr='#FFCCCCCC', GradientType=0)}.select2-container--classic .select2-selection--single .select2-selection__arrow b{border-color:#888 transparent transparent transparent;border-style:solid;border-width:5px 4px 0 4px;height:0;left:50%;margin-left:-4px;margin-top:-2px;position:absolute;top:50%;width:0}.select2-container--classic[dir="rtl"] .select2-selection--single .select2-selection__clear{float:left}.select2-container--classic[dir="rtl"] .select2-selection--single .select2-selection__arrow{border:none;border-right:1px solid #aaa;border-radius:0;border-top-left-radius:4px;border-bottom-left-radius:4px;left:1px;right:auto}.select2-container--classic.select2-container--open .select2-selection--single{border:1px solid #5897fb}.select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow{background:transparent;border:none}.select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow b{border-color:transparent transparent #888 transparent;border-width:0 4px 5px 4px}.select2-container--classic.select2-container--open.select2-container--above .select2-selection--single{border-top:none;border-top-left-radius:0;border-top-right-radius:0;background-image:-webkit-linear-gradient(top, #fff 0%, #eee 50%);background-image:-o-linear-gradient(top, #fff 0%, #eee 50%);background-image:linear-gradient(to bottom, #fff 0%, #eee 50%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFFFF', endColorstr='#FFEEEEEE', GradientType=0)}.select2-container--classic.select2-container--open.select2-container--below .select2-selection--single{border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0;background-image:-webkit-linear-gradient(top, #eee 50%, #fff 100%);background-image:-o-linear-gradient(top, #eee 50%, #fff 100%);background-image:linear-gradient(to bottom, #eee 50%, #fff 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFEEEEEE', endColorstr='#FFFFFFFF', GradientType=0)}.select2-container--classic .select2-selection--multiple{background-color:white;border:1px solid #aaa;border-radius:4px;cursor:text;outline:0;padding-bottom:5px;padding-right:5px}.select2-container--classic .select2-selection--multiple:focus{border:1px solid #5897fb}.select2-container--classic .select2-selection--multiple .select2-selection__clear{display:none}.select2-container--classic .select2-selection--multiple .select2-selection__choice{background-color:#e4e4e4;border:1px solid #aaa;border-radius:4px;display:inline-block;margin-left:5px;margin-top:5px;padding:0}.select2-container--classic .select2-selection--multiple .select2-selection__choice__display{cursor:default;padding-left:2px;padding-right:5px}.select2-container--classic .select2-selection--multiple .select2-selection__choice__remove{background-color:transparent;border:none;border-top-left-radius:4px;border-bottom-left-radius:4px;color:#888;cursor:pointer;font-size:1em;font-weight:bold;padding:0 4px}.select2-container--classic .select2-selection--multiple .select2-selection__choice__remove:hover{color:#555;outline:none}.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice{margin-left:5px;margin-right:auto}.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice__display{padding-left:5px;padding-right:2px}.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice__remove{border-top-left-radius:0;border-bottom-left-radius:0;border-top-right-radius:4px;border-bottom-right-radius:4px}.select2-container--classic.select2-container--open .select2-selection--multiple{border:1px solid #5897fb}.select2-container--classic.select2-container--open.select2-container--above .select2-selection--multiple{border-top:none;border-top-left-radius:0;border-top-right-radius:0}.select2-container--classic.select2-container--open.select2-container--below .select2-selection--multiple{border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0}.select2-container--classic .select2-search--dropdown .select2-search__field{border:1px solid #aaa;outline:0}.select2-container--classic .select2-search--inline .select2-search__field{outline:0;box-shadow:none}.select2-container--classic .select2-dropdown{background-color:#fff;border:1px solid transparent}.select2-container--classic .select2-dropdown--above{border-bottom:none}.select2-container--classic .select2-dropdown--below{border-top:none}.select2-container--classic .select2-results>.select2-results__options{max-height:200px;overflow-y:auto}.select2-container--classic .select2-results__option--group{padding:0}.select2-container--classic .select2-results__option--disabled{color:grey}.select2-container--classic .select2-results__option--highlighted.select2-results__option--selectable{background-color:#3875d7;color:#fff}.select2-container--classic .select2-results__group{cursor:default;display:block;padding:6px}.select2-container--classic.select2-container--open .select2-dropdown{border-color:#5897fb} \ No newline at end of file diff --git a/src/main/webapp/assets/libraries/select2/js/select2.min.js b/src/main/webapp/assets/libraries/select2/js/select2.min.js new file mode 100644 index 00000000..cc9a83f1 --- /dev/null +++ b/src/main/webapp/assets/libraries/select2/js/select2.min.js @@ -0,0 +1,2 @@ +/*! Select2 4.1.0-rc.0 | https://github.com/select2/select2/blob/master/LICENSE.md */ +!function(n){"function"==typeof define&&define.amd?define(["jquery"],n):"object"==typeof module&&module.exports?module.exports=function(e,t){return void 0===t&&(t="undefined"!=typeof window?require("jquery"):require("jquery")(e)),n(t),t}:n(jQuery)}(function(t){var e,n,s,p,r,o,h,f,g,m,y,v,i,a,_,s=((u=t&&t.fn&&t.fn.select2&&t.fn.select2.amd?t.fn.select2.amd:u)&&u.requirejs||(u?n=u:u={},g={},m={},y={},v={},i=Object.prototype.hasOwnProperty,a=[].slice,_=/\.js$/,h=function(e,t){var n,s,i=c(e),r=i[0],t=t[1];return e=i[1],r&&(n=x(r=l(r,t))),r?e=n&&n.normalize?n.normalize(e,(s=t,function(e){return l(e,s)})):l(e,t):(r=(i=c(e=l(e,t)))[0],e=i[1],r&&(n=x(r))),{f:r?r+"!"+e:e,n:e,pr:r,p:n}},f={require:function(e){return w(e)},exports:function(e){var t=g[e];return void 0!==t?t:g[e]={}},module:function(e){return{id:e,uri:"",exports:g[e],config:(t=e,function(){return y&&y.config&&y.config[t]||{}})};var t}},r=function(e,t,n,s){var i,r,o,a,l,c=[],u=typeof n,d=A(s=s||e);if("undefined"==u||"function"==u){for(t=!t.length&&n.length?["require","exports","module"]:t,a=0;a":">",'"':""","'":"'","/":"/"};return"string"!=typeof e?e:String(e).replace(/[&<>"'\/\\]/g,function(e){return t[e]})},s.__cache={};var n=0;return s.GetUniqueElementId=function(e){var t=e.getAttribute("data-select2-id");return null!=t||(t=e.id?"select2-data-"+e.id:"select2-data-"+(++n).toString()+"-"+s.generateChars(4),e.setAttribute("data-select2-id",t)),t},s.StoreData=function(e,t,n){e=s.GetUniqueElementId(e);s.__cache[e]||(s.__cache[e]={}),s.__cache[e][t]=n},s.GetData=function(e,t){var n=s.GetUniqueElementId(e);return t?s.__cache[n]&&null!=s.__cache[n][t]?s.__cache[n][t]:r(e).data(t):s.__cache[n]},s.RemoveData=function(e){var t=s.GetUniqueElementId(e);null!=s.__cache[t]&&delete s.__cache[t],e.removeAttribute("data-select2-id")},s.copyNonInternalCssClasses=function(e,t){var n=(n=e.getAttribute("class").trim().split(/\s+/)).filter(function(e){return 0===e.indexOf("select2-")}),t=(t=t.getAttribute("class").trim().split(/\s+/)).filter(function(e){return 0!==e.indexOf("select2-")}),t=n.concat(t);e.setAttribute("class",t.join(" "))},s}),u.define("select2/results",["jquery","./utils"],function(d,p){function s(e,t,n){this.$element=e,this.data=n,this.options=t,s.__super__.constructor.call(this)}return p.Extend(s,p.Observable),s.prototype.render=function(){var e=d('
      ');return this.options.get("multiple")&&e.attr("aria-multiselectable","true"),this.$results=e},s.prototype.clear=function(){this.$results.empty()},s.prototype.displayMessage=function(e){var t=this.options.get("escapeMarkup");this.clear(),this.hideLoading();var n=d(''),s=this.options.get("translations").get(e.message);n.append(t(s(e.args))),n[0].className+=" select2-results__message",this.$results.append(n)},s.prototype.hideMessages=function(){this.$results.find(".select2-results__message").remove()},s.prototype.append=function(e){this.hideLoading();var t=[];if(null!=e.results&&0!==e.results.length){e.results=this.sort(e.results);for(var n=0;n",{class:"select2-results__options select2-results__options--nested",role:"none"});i.append(l),o.append(a),o.append(i)}else this.template(e,t);return p.StoreData(t,"data",e),t},s.prototype.bind=function(t,e){var i=this,n=t.id+"-results";this.$results.attr("id",n),t.on("results:all",function(e){i.clear(),i.append(e.data),t.isOpen()&&(i.setClasses(),i.highlightFirstItem())}),t.on("results:append",function(e){i.append(e.data),t.isOpen()&&i.setClasses()}),t.on("query",function(e){i.hideMessages(),i.showLoading(e)}),t.on("select",function(){t.isOpen()&&(i.setClasses(),i.options.get("scrollAfterSelect")&&i.highlightFirstItem())}),t.on("unselect",function(){t.isOpen()&&(i.setClasses(),i.options.get("scrollAfterSelect")&&i.highlightFirstItem())}),t.on("open",function(){i.$results.attr("aria-expanded","true"),i.$results.attr("aria-hidden","false"),i.setClasses(),i.ensureHighlightVisible()}),t.on("close",function(){i.$results.attr("aria-expanded","false"),i.$results.attr("aria-hidden","true"),i.$results.removeAttr("aria-activedescendant")}),t.on("results:toggle",function(){var e=i.getHighlightedResults();0!==e.length&&e.trigger("mouseup")}),t.on("results:select",function(){var e,t=i.getHighlightedResults();0!==t.length&&(e=p.GetData(t[0],"data"),t.hasClass("select2-results__option--selected")?i.trigger("close",{}):i.trigger("select",{data:e}))}),t.on("results:previous",function(){var e,t=i.getHighlightedResults(),n=i.$results.find(".select2-results__option--selectable"),s=n.index(t);s<=0||(e=s-1,0===t.length&&(e=0),(s=n.eq(e)).trigger("mouseenter"),t=i.$results.offset().top,n=s.offset().top,s=i.$results.scrollTop()+(n-t),0===e?i.$results.scrollTop(0):n-t<0&&i.$results.scrollTop(s))}),t.on("results:next",function(){var e,t=i.getHighlightedResults(),n=i.$results.find(".select2-results__option--selectable"),s=n.index(t)+1;s>=n.length||((e=n.eq(s)).trigger("mouseenter"),t=i.$results.offset().top+i.$results.outerHeight(!1),n=e.offset().top+e.outerHeight(!1),e=i.$results.scrollTop()+n-t,0===s?i.$results.scrollTop(0):tthis.$results.outerHeight()||s<0)&&this.$results.scrollTop(n))},s.prototype.template=function(e,t){var n=this.options.get("templateResult"),s=this.options.get("escapeMarkup"),e=n(e,t);null==e?t.style.display="none":"string"==typeof e?t.innerHTML=s(e):d(t).append(e)},s}),u.define("select2/keys",[],function(){return{BACKSPACE:8,TAB:9,ENTER:13,SHIFT:16,CTRL:17,ALT:18,ESC:27,SPACE:32,PAGE_UP:33,PAGE_DOWN:34,END:35,HOME:36,LEFT:37,UP:38,RIGHT:39,DOWN:40,DELETE:46}}),u.define("select2/selection/base",["jquery","../utils","../keys"],function(n,s,i){function r(e,t){this.$element=e,this.options=t,r.__super__.constructor.call(this)}return s.Extend(r,s.Observable),r.prototype.render=function(){var e=n('');return this._tabindex=0,null!=s.GetData(this.$element[0],"old-tabindex")?this._tabindex=s.GetData(this.$element[0],"old-tabindex"):null!=this.$element.attr("tabindex")&&(this._tabindex=this.$element.attr("tabindex")),e.attr("title",this.$element.attr("title")),e.attr("tabindex",this._tabindex),e.attr("aria-disabled","false"),this.$selection=e},r.prototype.bind=function(e,t){var n=this,s=e.id+"-results";this.container=e,this.$selection.on("focus",function(e){n.trigger("focus",e)}),this.$selection.on("blur",function(e){n._handleBlur(e)}),this.$selection.on("keydown",function(e){n.trigger("keypress",e),e.which===i.SPACE&&e.preventDefault()}),e.on("results:focus",function(e){n.$selection.attr("aria-activedescendant",e.data._resultId)}),e.on("selection:update",function(e){n.update(e.data)}),e.on("open",function(){n.$selection.attr("aria-expanded","true"),n.$selection.attr("aria-owns",s),n._attachCloseHandler(e)}),e.on("close",function(){n.$selection.attr("aria-expanded","false"),n.$selection.removeAttr("aria-activedescendant"),n.$selection.removeAttr("aria-owns"),n.$selection.trigger("focus"),n._detachCloseHandler(e)}),e.on("enable",function(){n.$selection.attr("tabindex",n._tabindex),n.$selection.attr("aria-disabled","false")}),e.on("disable",function(){n.$selection.attr("tabindex","-1"),n.$selection.attr("aria-disabled","true")})},r.prototype._handleBlur=function(e){var t=this;window.setTimeout(function(){document.activeElement==t.$selection[0]||n.contains(t.$selection[0],document.activeElement)||t.trigger("blur",e)},1)},r.prototype._attachCloseHandler=function(e){n(document.body).on("mousedown.select2."+e.id,function(e){var t=n(e.target).closest(".select2");n(".select2.select2-container--open").each(function(){this!=t[0]&&s.GetData(this,"element").select2("close")})})},r.prototype._detachCloseHandler=function(e){n(document.body).off("mousedown.select2."+e.id)},r.prototype.position=function(e,t){t.find(".selection").append(e)},r.prototype.destroy=function(){this._detachCloseHandler(this.container)},r.prototype.update=function(e){throw new Error("The `update` method must be defined in child classes.")},r.prototype.isEnabled=function(){return!this.isDisabled()},r.prototype.isDisabled=function(){return this.options.get("disabled")},r}),u.define("select2/selection/single",["jquery","./base","../utils","../keys"],function(e,t,n,s){function i(){i.__super__.constructor.apply(this,arguments)}return n.Extend(i,t),i.prototype.render=function(){var e=i.__super__.render.call(this);return e[0].classList.add("select2-selection--single"),e.html(''),e},i.prototype.bind=function(t,e){var n=this;i.__super__.bind.apply(this,arguments);var s=t.id+"-container";this.$selection.find(".select2-selection__rendered").attr("id",s).attr("role","textbox").attr("aria-readonly","true"),this.$selection.attr("aria-labelledby",s),this.$selection.attr("aria-controls",s),this.$selection.on("mousedown",function(e){1===e.which&&n.trigger("toggle",{originalEvent:e})}),this.$selection.on("focus",function(e){}),this.$selection.on("blur",function(e){}),t.on("focus",function(e){t.isOpen()||n.$selection.trigger("focus")})},i.prototype.clear=function(){var e=this.$selection.find(".select2-selection__rendered");e.empty(),e.removeAttr("title")},i.prototype.display=function(e,t){var n=this.options.get("templateSelection");return this.options.get("escapeMarkup")(n(e,t))},i.prototype.selectionContainer=function(){return e("")},i.prototype.update=function(e){var t,n;0!==e.length?(n=e[0],t=this.$selection.find(".select2-selection__rendered"),e=this.display(n,t),t.empty().append(e),(n=n.title||n.text)?t.attr("title",n):t.removeAttr("title")):this.clear()},i}),u.define("select2/selection/multiple",["jquery","./base","../utils"],function(i,e,c){function r(e,t){r.__super__.constructor.apply(this,arguments)}return c.Extend(r,e),r.prototype.render=function(){var e=r.__super__.render.call(this);return e[0].classList.add("select2-selection--multiple"),e.html('
        '),e},r.prototype.bind=function(e,t){var n=this;r.__super__.bind.apply(this,arguments);var s=e.id+"-container";this.$selection.find(".select2-selection__rendered").attr("id",s),this.$selection.on("click",function(e){n.trigger("toggle",{originalEvent:e})}),this.$selection.on("click",".select2-selection__choice__remove",function(e){var t;n.isDisabled()||(t=i(this).parent(),t=c.GetData(t[0],"data"),n.trigger("unselect",{originalEvent:e,data:t}))}),this.$selection.on("keydown",".select2-selection__choice__remove",function(e){n.isDisabled()||e.stopPropagation()})},r.prototype.clear=function(){var e=this.$selection.find(".select2-selection__rendered");e.empty(),e.removeAttr("title")},r.prototype.display=function(e,t){var n=this.options.get("templateSelection");return this.options.get("escapeMarkup")(n(e,t))},r.prototype.selectionContainer=function(){return i('
      • ')},r.prototype.update=function(e){if(this.clear(),0!==e.length){for(var t=[],n=this.$selection.find(".select2-selection__rendered").attr("id")+"-choice-",s=0;s')).attr("title",s()),e.attr("aria-label",s()),e.attr("aria-describedby",n),a.StoreData(e[0],"data",t),this.$selection.prepend(e),this.$selection[0].classList.add("select2-selection--clearable"))},e}),u.define("select2/selection/search",["jquery","../utils","../keys"],function(s,a,l){function e(e,t,n){e.call(this,t,n)}return e.prototype.render=function(e){var t=this.options.get("translations").get("search"),n=s('');this.$searchContainer=n,this.$search=n.find("textarea"),this.$search.prop("autocomplete",this.options.get("autocomplete")),this.$search.attr("aria-label",t());e=e.call(this);return this._transferTabIndex(),e.append(this.$searchContainer),e},e.prototype.bind=function(e,t,n){var s=this,i=t.id+"-results",r=t.id+"-container";e.call(this,t,n),s.$search.attr("aria-describedby",r),t.on("open",function(){s.$search.attr("aria-controls",i),s.$search.trigger("focus")}),t.on("close",function(){s.$search.val(""),s.resizeSearch(),s.$search.removeAttr("aria-controls"),s.$search.removeAttr("aria-activedescendant"),s.$search.trigger("focus")}),t.on("enable",function(){s.$search.prop("disabled",!1),s._transferTabIndex()}),t.on("disable",function(){s.$search.prop("disabled",!0)}),t.on("focus",function(e){s.$search.trigger("focus")}),t.on("results:focus",function(e){e.data._resultId?s.$search.attr("aria-activedescendant",e.data._resultId):s.$search.removeAttr("aria-activedescendant")}),this.$selection.on("focusin",".select2-search--inline",function(e){s.trigger("focus",e)}),this.$selection.on("focusout",".select2-search--inline",function(e){s._handleBlur(e)}),this.$selection.on("keydown",".select2-search--inline",function(e){var t;e.stopPropagation(),s.trigger("keypress",e),s._keyUpPrevented=e.isDefaultPrevented(),e.which!==l.BACKSPACE||""!==s.$search.val()||0<(t=s.$selection.find(".select2-selection__choice").last()).length&&(t=a.GetData(t[0],"data"),s.searchRemoveChoice(t),e.preventDefault())}),this.$selection.on("click",".select2-search--inline",function(e){s.$search.val()&&e.stopPropagation()});var t=document.documentMode,o=t&&t<=11;this.$selection.on("input.searchcheck",".select2-search--inline",function(e){o?s.$selection.off("input.search input.searchcheck"):s.$selection.off("keyup.search")}),this.$selection.on("keyup.search input.search",".select2-search--inline",function(e){var t;o&&"input"===e.type?s.$selection.off("input.search input.searchcheck"):(t=e.which)!=l.SHIFT&&t!=l.CTRL&&t!=l.ALT&&t!=l.TAB&&s.handleSearch(e)})},e.prototype._transferTabIndex=function(e){this.$search.attr("tabindex",this.$selection.attr("tabindex")),this.$selection.attr("tabindex","-1")},e.prototype.createPlaceholder=function(e,t){this.$search.attr("placeholder",t.text)},e.prototype.update=function(e,t){var n=this.$search[0]==document.activeElement;this.$search.attr("placeholder",""),e.call(this,t),this.resizeSearch(),n&&this.$search.trigger("focus")},e.prototype.handleSearch=function(){var e;this.resizeSearch(),this._keyUpPrevented||(e=this.$search.val(),this.trigger("query",{term:e})),this._keyUpPrevented=!1},e.prototype.searchRemoveChoice=function(e,t){this.trigger("unselect",{data:t}),this.$search.val(t.text),this.handleSearch()},e.prototype.resizeSearch=function(){this.$search.css("width","25px");var e="100%";""===this.$search.attr("placeholder")&&(e=.75*(this.$search.val().length+1)+"em"),this.$search.css("width",e)},e}),u.define("select2/selection/selectionCss",["../utils"],function(n){function e(){}return e.prototype.render=function(e){var t=e.call(this),e=this.options.get("selectionCssClass")||"";return-1!==e.indexOf(":all:")&&(e=e.replace(":all:",""),n.copyNonInternalCssClasses(t[0],this.$element[0])),t.addClass(e),t},e}),u.define("select2/selection/eventRelay",["jquery"],function(o){function e(){}return e.prototype.bind=function(e,t,n){var s=this,i=["open","opening","close","closing","select","selecting","unselect","unselecting","clear","clearing"],r=["opening","closing","selecting","unselecting","clearing"];e.call(this,t,n),t.on("*",function(e,t){var n;-1!==i.indexOf(e)&&(t=t||{},n=o.Event("select2:"+e,{params:t}),s.$element.trigger(n),-1!==r.indexOf(e)&&(t.prevented=n.isDefaultPrevented()))})},e}),u.define("select2/translation",["jquery","require"],function(t,n){function s(e){this.dict=e||{}}return s.prototype.all=function(){return this.dict},s.prototype.get=function(e){return this.dict[e]},s.prototype.extend=function(e){this.dict=t.extend({},e.all(),this.dict)},s._cache={},s.loadPath=function(e){var t;return e in s._cache||(t=n(e),s._cache[e]=t),new s(s._cache[e])},s}),u.define("select2/diacritics",[],function(){return{"Ⓐ":"A","A":"A","À":"A","Á":"A","Â":"A","Ầ":"A","Ấ":"A","Ẫ":"A","Ẩ":"A","Ã":"A","Ā":"A","Ă":"A","Ằ":"A","Ắ":"A","Ẵ":"A","Ẳ":"A","Ȧ":"A","Ǡ":"A","Ä":"A","Ǟ":"A","Ả":"A","Å":"A","Ǻ":"A","Ǎ":"A","Ȁ":"A","Ȃ":"A","Ạ":"A","Ậ":"A","Ặ":"A","Ḁ":"A","Ą":"A","Ⱥ":"A","Ɐ":"A","Ꜳ":"AA","Æ":"AE","Ǽ":"AE","Ǣ":"AE","Ꜵ":"AO","Ꜷ":"AU","Ꜹ":"AV","Ꜻ":"AV","Ꜽ":"AY","Ⓑ":"B","B":"B","Ḃ":"B","Ḅ":"B","Ḇ":"B","Ƀ":"B","Ƃ":"B","Ɓ":"B","Ⓒ":"C","C":"C","Ć":"C","Ĉ":"C","Ċ":"C","Č":"C","Ç":"C","Ḉ":"C","Ƈ":"C","Ȼ":"C","Ꜿ":"C","Ⓓ":"D","D":"D","Ḋ":"D","Ď":"D","Ḍ":"D","Ḑ":"D","Ḓ":"D","Ḏ":"D","Đ":"D","Ƌ":"D","Ɗ":"D","Ɖ":"D","Ꝺ":"D","DZ":"DZ","DŽ":"DZ","Dz":"Dz","Dž":"Dz","Ⓔ":"E","E":"E","È":"E","É":"E","Ê":"E","Ề":"E","Ế":"E","Ễ":"E","Ể":"E","Ẽ":"E","Ē":"E","Ḕ":"E","Ḗ":"E","Ĕ":"E","Ė":"E","Ë":"E","Ẻ":"E","Ě":"E","Ȅ":"E","Ȇ":"E","Ẹ":"E","Ệ":"E","Ȩ":"E","Ḝ":"E","Ę":"E","Ḙ":"E","Ḛ":"E","Ɛ":"E","Ǝ":"E","Ⓕ":"F","F":"F","Ḟ":"F","Ƒ":"F","Ꝼ":"F","Ⓖ":"G","G":"G","Ǵ":"G","Ĝ":"G","Ḡ":"G","Ğ":"G","Ġ":"G","Ǧ":"G","Ģ":"G","Ǥ":"G","Ɠ":"G","Ꞡ":"G","Ᵹ":"G","Ꝿ":"G","Ⓗ":"H","H":"H","Ĥ":"H","Ḣ":"H","Ḧ":"H","Ȟ":"H","Ḥ":"H","Ḩ":"H","Ḫ":"H","Ħ":"H","Ⱨ":"H","Ⱶ":"H","Ɥ":"H","Ⓘ":"I","I":"I","Ì":"I","Í":"I","Î":"I","Ĩ":"I","Ī":"I","Ĭ":"I","İ":"I","Ï":"I","Ḯ":"I","Ỉ":"I","Ǐ":"I","Ȉ":"I","Ȋ":"I","Ị":"I","Į":"I","Ḭ":"I","Ɨ":"I","Ⓙ":"J","J":"J","Ĵ":"J","Ɉ":"J","Ⓚ":"K","K":"K","Ḱ":"K","Ǩ":"K","Ḳ":"K","Ķ":"K","Ḵ":"K","Ƙ":"K","Ⱪ":"K","Ꝁ":"K","Ꝃ":"K","Ꝅ":"K","Ꞣ":"K","Ⓛ":"L","L":"L","Ŀ":"L","Ĺ":"L","Ľ":"L","Ḷ":"L","Ḹ":"L","Ļ":"L","Ḽ":"L","Ḻ":"L","Ł":"L","Ƚ":"L","Ɫ":"L","Ⱡ":"L","Ꝉ":"L","Ꝇ":"L","Ꞁ":"L","LJ":"LJ","Lj":"Lj","Ⓜ":"M","M":"M","Ḿ":"M","Ṁ":"M","Ṃ":"M","Ɱ":"M","Ɯ":"M","Ⓝ":"N","N":"N","Ǹ":"N","Ń":"N","Ñ":"N","Ṅ":"N","Ň":"N","Ṇ":"N","Ņ":"N","Ṋ":"N","Ṉ":"N","Ƞ":"N","Ɲ":"N","Ꞑ":"N","Ꞥ":"N","NJ":"NJ","Nj":"Nj","Ⓞ":"O","O":"O","Ò":"O","Ó":"O","Ô":"O","Ồ":"O","Ố":"O","Ỗ":"O","Ổ":"O","Õ":"O","Ṍ":"O","Ȭ":"O","Ṏ":"O","Ō":"O","Ṑ":"O","Ṓ":"O","Ŏ":"O","Ȯ":"O","Ȱ":"O","Ö":"O","Ȫ":"O","Ỏ":"O","Ő":"O","Ǒ":"O","Ȍ":"O","Ȏ":"O","Ơ":"O","Ờ":"O","Ớ":"O","Ỡ":"O","Ở":"O","Ợ":"O","Ọ":"O","Ộ":"O","Ǫ":"O","Ǭ":"O","Ø":"O","Ǿ":"O","Ɔ":"O","Ɵ":"O","Ꝋ":"O","Ꝍ":"O","Œ":"OE","Ƣ":"OI","Ꝏ":"OO","Ȣ":"OU","Ⓟ":"P","P":"P","Ṕ":"P","Ṗ":"P","Ƥ":"P","Ᵽ":"P","Ꝑ":"P","Ꝓ":"P","Ꝕ":"P","Ⓠ":"Q","Q":"Q","Ꝗ":"Q","Ꝙ":"Q","Ɋ":"Q","Ⓡ":"R","R":"R","Ŕ":"R","Ṙ":"R","Ř":"R","Ȑ":"R","Ȓ":"R","Ṛ":"R","Ṝ":"R","Ŗ":"R","Ṟ":"R","Ɍ":"R","Ɽ":"R","Ꝛ":"R","Ꞧ":"R","Ꞃ":"R","Ⓢ":"S","S":"S","ẞ":"S","Ś":"S","Ṥ":"S","Ŝ":"S","Ṡ":"S","Š":"S","Ṧ":"S","Ṣ":"S","Ṩ":"S","Ș":"S","Ş":"S","Ȿ":"S","Ꞩ":"S","Ꞅ":"S","Ⓣ":"T","T":"T","Ṫ":"T","Ť":"T","Ṭ":"T","Ț":"T","Ţ":"T","Ṱ":"T","Ṯ":"T","Ŧ":"T","Ƭ":"T","Ʈ":"T","Ⱦ":"T","Ꞇ":"T","Ꜩ":"TZ","Ⓤ":"U","U":"U","Ù":"U","Ú":"U","Û":"U","Ũ":"U","Ṹ":"U","Ū":"U","Ṻ":"U","Ŭ":"U","Ü":"U","Ǜ":"U","Ǘ":"U","Ǖ":"U","Ǚ":"U","Ủ":"U","Ů":"U","Ű":"U","Ǔ":"U","Ȕ":"U","Ȗ":"U","Ư":"U","Ừ":"U","Ứ":"U","Ữ":"U","Ử":"U","Ự":"U","Ụ":"U","Ṳ":"U","Ų":"U","Ṷ":"U","Ṵ":"U","Ʉ":"U","Ⓥ":"V","V":"V","Ṽ":"V","Ṿ":"V","Ʋ":"V","Ꝟ":"V","Ʌ":"V","Ꝡ":"VY","Ⓦ":"W","W":"W","Ẁ":"W","Ẃ":"W","Ŵ":"W","Ẇ":"W","Ẅ":"W","Ẉ":"W","Ⱳ":"W","Ⓧ":"X","X":"X","Ẋ":"X","Ẍ":"X","Ⓨ":"Y","Y":"Y","Ỳ":"Y","Ý":"Y","Ŷ":"Y","Ỹ":"Y","Ȳ":"Y","Ẏ":"Y","Ÿ":"Y","Ỷ":"Y","Ỵ":"Y","Ƴ":"Y","Ɏ":"Y","Ỿ":"Y","Ⓩ":"Z","Z":"Z","Ź":"Z","Ẑ":"Z","Ż":"Z","Ž":"Z","Ẓ":"Z","Ẕ":"Z","Ƶ":"Z","Ȥ":"Z","Ɀ":"Z","Ⱬ":"Z","Ꝣ":"Z","ⓐ":"a","a":"a","ẚ":"a","à":"a","á":"a","â":"a","ầ":"a","ấ":"a","ẫ":"a","ẩ":"a","ã":"a","ā":"a","ă":"a","ằ":"a","ắ":"a","ẵ":"a","ẳ":"a","ȧ":"a","ǡ":"a","ä":"a","ǟ":"a","ả":"a","å":"a","ǻ":"a","ǎ":"a","ȁ":"a","ȃ":"a","ạ":"a","ậ":"a","ặ":"a","ḁ":"a","ą":"a","ⱥ":"a","ɐ":"a","ꜳ":"aa","æ":"ae","ǽ":"ae","ǣ":"ae","ꜵ":"ao","ꜷ":"au","ꜹ":"av","ꜻ":"av","ꜽ":"ay","ⓑ":"b","b":"b","ḃ":"b","ḅ":"b","ḇ":"b","ƀ":"b","ƃ":"b","ɓ":"b","ⓒ":"c","c":"c","ć":"c","ĉ":"c","ċ":"c","č":"c","ç":"c","ḉ":"c","ƈ":"c","ȼ":"c","ꜿ":"c","ↄ":"c","ⓓ":"d","d":"d","ḋ":"d","ď":"d","ḍ":"d","ḑ":"d","ḓ":"d","ḏ":"d","đ":"d","ƌ":"d","ɖ":"d","ɗ":"d","ꝺ":"d","dz":"dz","dž":"dz","ⓔ":"e","e":"e","è":"e","é":"e","ê":"e","ề":"e","ế":"e","ễ":"e","ể":"e","ẽ":"e","ē":"e","ḕ":"e","ḗ":"e","ĕ":"e","ė":"e","ë":"e","ẻ":"e","ě":"e","ȅ":"e","ȇ":"e","ẹ":"e","ệ":"e","ȩ":"e","ḝ":"e","ę":"e","ḙ":"e","ḛ":"e","ɇ":"e","ɛ":"e","ǝ":"e","ⓕ":"f","f":"f","ḟ":"f","ƒ":"f","ꝼ":"f","ⓖ":"g","g":"g","ǵ":"g","ĝ":"g","ḡ":"g","ğ":"g","ġ":"g","ǧ":"g","ģ":"g","ǥ":"g","ɠ":"g","ꞡ":"g","ᵹ":"g","ꝿ":"g","ⓗ":"h","h":"h","ĥ":"h","ḣ":"h","ḧ":"h","ȟ":"h","ḥ":"h","ḩ":"h","ḫ":"h","ẖ":"h","ħ":"h","ⱨ":"h","ⱶ":"h","ɥ":"h","ƕ":"hv","ⓘ":"i","i":"i","ì":"i","í":"i","î":"i","ĩ":"i","ī":"i","ĭ":"i","ï":"i","ḯ":"i","ỉ":"i","ǐ":"i","ȉ":"i","ȋ":"i","ị":"i","į":"i","ḭ":"i","ɨ":"i","ı":"i","ⓙ":"j","j":"j","ĵ":"j","ǰ":"j","ɉ":"j","ⓚ":"k","k":"k","ḱ":"k","ǩ":"k","ḳ":"k","ķ":"k","ḵ":"k","ƙ":"k","ⱪ":"k","ꝁ":"k","ꝃ":"k","ꝅ":"k","ꞣ":"k","ⓛ":"l","l":"l","ŀ":"l","ĺ":"l","ľ":"l","ḷ":"l","ḹ":"l","ļ":"l","ḽ":"l","ḻ":"l","ſ":"l","ł":"l","ƚ":"l","ɫ":"l","ⱡ":"l","ꝉ":"l","ꞁ":"l","ꝇ":"l","lj":"lj","ⓜ":"m","m":"m","ḿ":"m","ṁ":"m","ṃ":"m","ɱ":"m","ɯ":"m","ⓝ":"n","n":"n","ǹ":"n","ń":"n","ñ":"n","ṅ":"n","ň":"n","ṇ":"n","ņ":"n","ṋ":"n","ṉ":"n","ƞ":"n","ɲ":"n","ʼn":"n","ꞑ":"n","ꞥ":"n","nj":"nj","ⓞ":"o","o":"o","ò":"o","ó":"o","ô":"o","ồ":"o","ố":"o","ỗ":"o","ổ":"o","õ":"o","ṍ":"o","ȭ":"o","ṏ":"o","ō":"o","ṑ":"o","ṓ":"o","ŏ":"o","ȯ":"o","ȱ":"o","ö":"o","ȫ":"o","ỏ":"o","ő":"o","ǒ":"o","ȍ":"o","ȏ":"o","ơ":"o","ờ":"o","ớ":"o","ỡ":"o","ở":"o","ợ":"o","ọ":"o","ộ":"o","ǫ":"o","ǭ":"o","ø":"o","ǿ":"o","ɔ":"o","ꝋ":"o","ꝍ":"o","ɵ":"o","œ":"oe","ƣ":"oi","ȣ":"ou","ꝏ":"oo","ⓟ":"p","p":"p","ṕ":"p","ṗ":"p","ƥ":"p","ᵽ":"p","ꝑ":"p","ꝓ":"p","ꝕ":"p","ⓠ":"q","q":"q","ɋ":"q","ꝗ":"q","ꝙ":"q","ⓡ":"r","r":"r","ŕ":"r","ṙ":"r","ř":"r","ȑ":"r","ȓ":"r","ṛ":"r","ṝ":"r","ŗ":"r","ṟ":"r","ɍ":"r","ɽ":"r","ꝛ":"r","ꞧ":"r","ꞃ":"r","ⓢ":"s","s":"s","ß":"s","ś":"s","ṥ":"s","ŝ":"s","ṡ":"s","š":"s","ṧ":"s","ṣ":"s","ṩ":"s","ș":"s","ş":"s","ȿ":"s","ꞩ":"s","ꞅ":"s","ẛ":"s","ⓣ":"t","t":"t","ṫ":"t","ẗ":"t","ť":"t","ṭ":"t","ț":"t","ţ":"t","ṱ":"t","ṯ":"t","ŧ":"t","ƭ":"t","ʈ":"t","ⱦ":"t","ꞇ":"t","ꜩ":"tz","ⓤ":"u","u":"u","ù":"u","ú":"u","û":"u","ũ":"u","ṹ":"u","ū":"u","ṻ":"u","ŭ":"u","ü":"u","ǜ":"u","ǘ":"u","ǖ":"u","ǚ":"u","ủ":"u","ů":"u","ű":"u","ǔ":"u","ȕ":"u","ȗ":"u","ư":"u","ừ":"u","ứ":"u","ữ":"u","ử":"u","ự":"u","ụ":"u","ṳ":"u","ų":"u","ṷ":"u","ṵ":"u","ʉ":"u","ⓥ":"v","v":"v","ṽ":"v","ṿ":"v","ʋ":"v","ꝟ":"v","ʌ":"v","ꝡ":"vy","ⓦ":"w","w":"w","ẁ":"w","ẃ":"w","ŵ":"w","ẇ":"w","ẅ":"w","ẘ":"w","ẉ":"w","ⱳ":"w","ⓧ":"x","x":"x","ẋ":"x","ẍ":"x","ⓨ":"y","y":"y","ỳ":"y","ý":"y","ŷ":"y","ỹ":"y","ȳ":"y","ẏ":"y","ÿ":"y","ỷ":"y","ẙ":"y","ỵ":"y","ƴ":"y","ɏ":"y","ỿ":"y","ⓩ":"z","z":"z","ź":"z","ẑ":"z","ż":"z","ž":"z","ẓ":"z","ẕ":"z","ƶ":"z","ȥ":"z","ɀ":"z","ⱬ":"z","ꝣ":"z","Ά":"Α","Έ":"Ε","Ή":"Η","Ί":"Ι","Ϊ":"Ι","Ό":"Ο","Ύ":"Υ","Ϋ":"Υ","Ώ":"Ω","ά":"α","έ":"ε","ή":"η","ί":"ι","ϊ":"ι","ΐ":"ι","ό":"ο","ύ":"υ","ϋ":"υ","ΰ":"υ","ώ":"ω","ς":"σ","’":"'"}}),u.define("select2/data/base",["../utils"],function(n){function s(e,t){s.__super__.constructor.call(this)}return n.Extend(s,n.Observable),s.prototype.current=function(e){throw new Error("The `current` method must be defined in child classes.")},s.prototype.query=function(e,t){throw new Error("The `query` method must be defined in child classes.")},s.prototype.bind=function(e,t){},s.prototype.destroy=function(){},s.prototype.generateResultId=function(e,t){e=e.id+"-result-";return e+=n.generateChars(4),null!=t.id?e+="-"+t.id.toString():e+="-"+n.generateChars(4),e},s}),u.define("select2/data/select",["./base","../utils","jquery"],function(e,a,l){function n(e,t){this.$element=e,this.options=t,n.__super__.constructor.call(this)}return a.Extend(n,e),n.prototype.current=function(e){var t=this;e(Array.prototype.map.call(this.$element[0].querySelectorAll(":checked"),function(e){return t.item(l(e))}))},n.prototype.select=function(i){var e,r=this;if(i.selected=!0,null!=i.element&&"option"===i.element.tagName.toLowerCase())return i.element.selected=!0,void this.$element.trigger("input").trigger("change");this.$element.prop("multiple")?this.current(function(e){var t=[];(i=[i]).push.apply(i,e);for(var n=0;nthis.maximumInputLength?this.trigger("results:message",{message:"inputTooLong",args:{maximum:this.maximumInputLength,input:t.term,params:t}}):e.call(this,t,n)},e}),u.define("select2/data/maximumSelectionLength",[],function(){function e(e,t,n){this.maximumSelectionLength=n.get("maximumSelectionLength"),e.call(this,t,n)}return e.prototype.bind=function(e,t,n){var s=this;e.call(this,t,n),t.on("select",function(){s._checkIfMaximumSelected()})},e.prototype.query=function(e,t,n){var s=this;this._checkIfMaximumSelected(function(){e.call(s,t,n)})},e.prototype._checkIfMaximumSelected=function(e,t){var n=this;this.current(function(e){e=null!=e?e.length:0;0=n.maximumSelectionLength?n.trigger("results:message",{message:"maximumSelected",args:{maximum:n.maximumSelectionLength}}):t&&t()})},e}),u.define("select2/dropdown",["jquery","./utils"],function(t,e){function n(e,t){this.$element=e,this.options=t,n.__super__.constructor.call(this)}return e.Extend(n,e.Observable),n.prototype.render=function(){var e=t('');return e.attr("dir",this.options.get("dir")),this.$dropdown=e},n.prototype.bind=function(){},n.prototype.position=function(e,t){},n.prototype.destroy=function(){this.$dropdown.remove()},n}),u.define("select2/dropdown/search",["jquery"],function(r){function e(){}return e.prototype.render=function(e){var t=e.call(this),n=this.options.get("translations").get("search"),e=r('');return this.$searchContainer=e,this.$search=e.find("input"),this.$search.prop("autocomplete",this.options.get("autocomplete")),this.$search.attr("aria-label",n()),t.prepend(e),t},e.prototype.bind=function(e,t,n){var s=this,i=t.id+"-results";e.call(this,t,n),this.$search.on("keydown",function(e){s.trigger("keypress",e),s._keyUpPrevented=e.isDefaultPrevented()}),this.$search.on("input",function(e){r(this).off("keyup")}),this.$search.on("keyup input",function(e){s.handleSearch(e)}),t.on("open",function(){s.$search.attr("tabindex",0),s.$search.attr("aria-controls",i),s.$search.trigger("focus"),window.setTimeout(function(){s.$search.trigger("focus")},0)}),t.on("close",function(){s.$search.attr("tabindex",-1),s.$search.removeAttr("aria-controls"),s.$search.removeAttr("aria-activedescendant"),s.$search.val(""),s.$search.trigger("blur")}),t.on("focus",function(){t.isOpen()||s.$search.trigger("focus")}),t.on("results:all",function(e){null!=e.query.term&&""!==e.query.term||(s.showSearch(e)?s.$searchContainer[0].classList.remove("select2-search--hide"):s.$searchContainer[0].classList.add("select2-search--hide"))}),t.on("results:focus",function(e){e.data._resultId?s.$search.attr("aria-activedescendant",e.data._resultId):s.$search.removeAttr("aria-activedescendant")})},e.prototype.handleSearch=function(e){var t;this._keyUpPrevented||(t=this.$search.val(),this.trigger("query",{term:t})),this._keyUpPrevented=!1},e.prototype.showSearch=function(e,t){return!0},e}),u.define("select2/dropdown/hidePlaceholder",[],function(){function e(e,t,n,s){this.placeholder=this.normalizePlaceholder(n.get("placeholder")),e.call(this,t,n,s)}return e.prototype.append=function(e,t){t.results=this.removePlaceholder(t.results),e.call(this,t)},e.prototype.normalizePlaceholder=function(e,t){return t="string"==typeof t?{id:"",text:t}:t},e.prototype.removePlaceholder=function(e,t){for(var n=t.slice(0),s=t.length-1;0<=s;s--){var i=t[s];this.placeholder.id===i.id&&n.splice(s,1)}return n},e}),u.define("select2/dropdown/infiniteScroll",["jquery"],function(n){function e(e,t,n,s){this.lastParams={},e.call(this,t,n,s),this.$loadingMore=this.createLoadingMore(),this.loading=!1}return e.prototype.append=function(e,t){this.$loadingMore.remove(),this.loading=!1,e.call(this,t),this.showLoadingMore(t)&&(this.$results.append(this.$loadingMore),this.loadMoreIfNeeded())},e.prototype.bind=function(e,t,n){var s=this;e.call(this,t,n),t.on("query",function(e){s.lastParams=e,s.loading=!0}),t.on("query:append",function(e){s.lastParams=e,s.loading=!0}),this.$results.on("scroll",this.loadMoreIfNeeded.bind(this))},e.prototype.loadMoreIfNeeded=function(){var e=n.contains(document.documentElement,this.$loadingMore[0]);!this.loading&&e&&(e=this.$results.offset().top+this.$results.outerHeight(!1),this.$loadingMore.offset().top+this.$loadingMore.outerHeight(!1)<=e+50&&this.loadMore())},e.prototype.loadMore=function(){this.loading=!0;var e=n.extend({},{page:1},this.lastParams);e.page++,this.trigger("query:append",e)},e.prototype.showLoadingMore=function(e,t){return t.pagination&&t.pagination.more},e.prototype.createLoadingMore=function(){var e=n('
      • '),t=this.options.get("translations").get("loadingMore");return e.html(t(this.lastParams)),e},e}),u.define("select2/dropdown/attachBody",["jquery","../utils"],function(u,o){function e(e,t,n){this.$dropdownParent=u(n.get("dropdownParent")||document.body),e.call(this,t,n)}return e.prototype.bind=function(e,t,n){var s=this;e.call(this,t,n),t.on("open",function(){s._showDropdown(),s._attachPositioningHandler(t),s._bindContainerResultHandlers(t)}),t.on("close",function(){s._hideDropdown(),s._detachPositioningHandler(t)}),this.$dropdownContainer.on("mousedown",function(e){e.stopPropagation()})},e.prototype.destroy=function(e){e.call(this),this.$dropdownContainer.remove()},e.prototype.position=function(e,t,n){t.attr("class",n.attr("class")),t[0].classList.remove("select2"),t[0].classList.add("select2-container--open"),t.css({position:"absolute",top:-999999}),this.$container=n},e.prototype.render=function(e){var t=u(""),e=e.call(this);return t.append(e),this.$dropdownContainer=t},e.prototype._hideDropdown=function(e){this.$dropdownContainer.detach()},e.prototype._bindContainerResultHandlers=function(e,t){var n;this._containerResultsHandlersBound||(n=this,t.on("results:all",function(){n._positionDropdown(),n._resizeDropdown()}),t.on("results:append",function(){n._positionDropdown(),n._resizeDropdown()}),t.on("results:message",function(){n._positionDropdown(),n._resizeDropdown()}),t.on("select",function(){n._positionDropdown(),n._resizeDropdown()}),t.on("unselect",function(){n._positionDropdown(),n._resizeDropdown()}),this._containerResultsHandlersBound=!0)},e.prototype._attachPositioningHandler=function(e,t){var n=this,s="scroll.select2."+t.id,i="resize.select2."+t.id,r="orientationchange.select2."+t.id,t=this.$container.parents().filter(o.hasScroll);t.each(function(){o.StoreData(this,"select2-scroll-position",{x:u(this).scrollLeft(),y:u(this).scrollTop()})}),t.on(s,function(e){var t=o.GetData(this,"select2-scroll-position");u(this).scrollTop(t.y)}),u(window).on(s+" "+i+" "+r,function(e){n._positionDropdown(),n._resizeDropdown()})},e.prototype._detachPositioningHandler=function(e,t){var n="scroll.select2."+t.id,s="resize.select2."+t.id,t="orientationchange.select2."+t.id;this.$container.parents().filter(o.hasScroll).off(n),u(window).off(n+" "+s+" "+t)},e.prototype._positionDropdown=function(){var e=u(window),t=this.$dropdown[0].classList.contains("select2-dropdown--above"),n=this.$dropdown[0].classList.contains("select2-dropdown--below"),s=null,i=this.$container.offset();i.bottom=i.top+this.$container.outerHeight(!1);var r={height:this.$container.outerHeight(!1)};r.top=i.top,r.bottom=i.top+r.height;var o=this.$dropdown.outerHeight(!1),a=e.scrollTop(),l=e.scrollTop()+e.height(),c=ai.bottom+o,a={left:i.left,top:r.bottom},l=this.$dropdownParent;"static"===l.css("position")&&(l=l.offsetParent());i={top:0,left:0};(u.contains(document.body,l[0])||l[0].isConnected)&&(i=l.offset()),a.top-=i.top,a.left-=i.left,t||n||(s="below"),e||!c||t?!c&&e&&t&&(s="below"):s="above",("above"==s||t&&"below"!==s)&&(a.top=r.top-i.top-o),null!=s&&(this.$dropdown[0].classList.remove("select2-dropdown--below"),this.$dropdown[0].classList.remove("select2-dropdown--above"),this.$dropdown[0].classList.add("select2-dropdown--"+s),this.$container[0].classList.remove("select2-container--below"),this.$container[0].classList.remove("select2-container--above"),this.$container[0].classList.add("select2-container--"+s)),this.$dropdownContainer.css(a)},e.prototype._resizeDropdown=function(){var e={width:this.$container.outerWidth(!1)+"px"};this.options.get("dropdownAutoWidth")&&(e.minWidth=e.width,e.position="relative",e.width="auto"),this.$dropdown.css(e)},e.prototype._showDropdown=function(e){this.$dropdownContainer.appendTo(this.$dropdownParent),this._positionDropdown(),this._resizeDropdown()},e}),u.define("select2/dropdown/minimumResultsForSearch",[],function(){function e(e,t,n,s){this.minimumResultsForSearch=n.get("minimumResultsForSearch"),this.minimumResultsForSearch<0&&(this.minimumResultsForSearch=1/0),e.call(this,t,n,s)}return e.prototype.showSearch=function(e,t){return!(function e(t){for(var n=0,s=0;s');return e.attr("dir",this.options.get("dir")),this.$container=e,this.$container[0].classList.add("select2-container--"+this.options.get("theme")),r.StoreData(e[0],"element",this.$element),e},o}),u.define("jquery-mousewheel",["jquery"],function(e){return e}),u.define("jquery.select2",["jquery","jquery-mousewheel","./select2/core","./select2/defaults","./select2/utils"],function(i,e,r,t,o){var a;return null==i.fn.select2&&(a=["open","close","destroy"],i.fn.select2=function(t){if("object"==typeof(t=t||{}))return this.each(function(){var e=i.extend(!0,{},t);new r(i(this),e)}),this;if("string"!=typeof t)throw new Error("Invalid arguments for Select2: "+t);var n,s=Array.prototype.slice.call(arguments,1);return this.each(function(){var e=o.GetData(this,"select2");null==e&&window.console&&console.error&&console.error("The select2('"+t+"') method was called on an element that is not using Select2."),n=e[t].apply(e,s)}),-1Não há especialidades"); + // } else + // $('#expertise-select').removeAttr("disabled"); + // $("#expertise-select").append(""); + // + // $.each(expertises, function (index, expertise) { + // + // if(expertise.id == element){ + // $("#expertise-select").append(""); + // }else { + // $("#expertise-select").append(""); + // } + // + // }); + // $("#expertise-select").formSelect(); + // } + // }); + // } + // if ($("#expertise-select").val() != '') { + // selectExpertise(element) + // } + // + // var element_service = $("#dto_service").val(); + // function selectExpertise(expertiseId) { + // $.ajax({ + // url: "servicos/especialidade/"+ expertiseId, + // type: "GET", + // success: function (services) { + // + // $("#service-select").empty(); + // + // //se o array for vazio, coloca o option que não há especialidades + // if (services.length === 0) { + // $('#service-select').prop("disabled", true); + // $("#service-select").append(""); + // } else + // $('#service-select').removeAttr("disabled"); + // $("#service-select").append(""); + // + // $.each(services, function (index, service) { + // $("#service-select").append(""); + // + // if(service.id == element_service){ + // $("#service-select").append(""); + // }else { + // $("#service-select").append(""); + // } + // + // }); + // $("#service-select").formSelect(); + // } + // }); + // } + // + // // LISTA DE ESPECIALIDADE DE ACORDO COM A CATEGORIA + // $("#category-select").change(function () { + // let categoryId = $(this).val(); + // $.ajax({ + // url: "especialidades/categoria/"+ categoryId, + // type: "GET", + // success: function (expertises) { + // console.log(expertises) + // + // $("#expertise-select").empty(); + // + // //se o array for vazio, coloca o option que não há especialidades + // if (expertises.length === 0) + // $("#expertise-select").append(""); + // else + // $("#expertise-select").append(""); + // + // $.each(expertises, function (index, expertise) { + // $("#expertise-select").append(""); + // }); + // $("#expertise-select").formSelect(); + // } + // }); + // }); + // + // // LISTA DE SERVIÇOS DE ACORDO COM A ESPECIALIDADE + // $("#expertise-select").change(function () { + // let expertiseId = $(this).val(); + // $.ajax({ + // url: "servicos/especialidade/"+ expertiseId, + // type: "GET", + // success: function (services) { + // + // $("#service-select").empty(); + // + // //se o array for vazio, coloca o option que não há especialidades + // if (services.length === 0) + // $("#service-select").append(""); + // else + // $("#service-select").append(""); + // + // $.each(services, function (index, service) { + // $("#service-select").append(""); + // + // }); + // $("#service-select").formSelect(); + // } + // }); + // }); + // get card width dynamically + cardWidth = $(".slide-card").width(); + // next-arrow + $('#next-arrow').click(function () { + var firstChildAppend = $(".slide-card:first-child()"); + $(".slide-card").animate({ left: -cardWidth }, function () { + $('.slider-wrap').append(firstChildAppend); + $(".slide-card").css({ + left: 0, + }) + }) + }); + // previous-arrow + $('#previous-arrow').click(function () { + var lastChildPrepend = $(".slide-card:last-child()"); + $(".slide-card").animate({ left: cardWidth }, function () { + $('.slider-wrap').prepend(lastChildPrepend); + $(".slide-card").css({ + left: 0, + }) + }) + }); + + + // MEUS ANUNCIOS + $(function () { + // adiciona mascara no campo de valor + $('.ads-price').mask('000.000.000.000.000,00', {reverse: true}); + + // inicializa os campos nome e descrição com os dados do serviço selecionado + $('#service-select-individual').change(function () { + let serviceId = $(this).val(); + let url = 'servicos/' + serviceId; + + $.get(url, function (data) { + $('#name-input').val(data.name); + $('#description-textarea').val(data.description); + $('#description-blockquote').show(); + }); + }); + + // inicializa o select de serviços com os serviços da especialidade selecionada + $('#expertise-select').change(function () { + let expertiseId = $(this).val(); + let url = 'minha-conta/profissional/especialidades/' + expertiseId + '/servicos'; + + $.get(url, function (data) { + let options = ''; + data.forEach(function (service) { + options += ''; + }); + $('#service-select-individual').html(options); + $('#service-select-individual').formSelect(); + }); + }); + }); + //seleciona o tipo do serviço, habilitando desta forma cada formulario de acordo com o tipo + $('#service-type').change(function () { + let type = $(this).val(); + if(type == 'SIMPLE_PACKAGE'){ + $('#type-package').show(); + } else { + $('#type-package').hide(); + } + + if(type == 'COMBINED_PACKAGE') { + $('#type-combined').show(); + $('#ads-name').hide(); + $('#label-ads').hide(); + } else { + $('#type-combined').hide(); + } + if(type == 'INDIVIDUAL'){ + $('.type-individual').show(); + }else { + $('.type-individual').hide(); + } + + }); + //adiciona o valor do select e adiciona no campo de texo + $('#service-select-individual').change(function () { + var select = document.getElementById("service-select-individual"); + var opcaoTexto = select.options[select.selectedIndex].text; + var opcaoValor = select.options[select.selectedIndex].value; + $(".ads-name").val(opcaoTexto); + $(".name-service").val(opcaoTexto); + }); + + $('#service-select-package').change(function () { + var select = document.getElementById("service-select-package"); + var opcaoTexto = select.options[select.selectedIndex].text; + var opcaoValor = select.options[select.selectedIndex].value; + $(".ads-name").val(opcaoTexto); + $(".name-service").val(opcaoTexto); + }); + + $('#service-select-combined').change(function () { + var selectElement = document.getElementById("service-select-combined"); + var opcaoTexto = select.options[select.selectedIndex].text; + var opcaoValor = select.options[select.selectedIndex].value; + + + var selectedOptions = selectElement.selectedOptions; + // + console.log(selectedOptions) + // // Cria um array para armazenar os textos selecionados + // var selectedTexts = []; + // + // // Loop pelas opções selecionadas e adiciona seus textos ao array + // for (var i = 0; i < selectedOptions.length; i++) { + // selectedTexts.push(selectedOptions[i].text); + // } + // + // // Obtém o campo input + // $(".ads-name").val(selectedTexts.join(", ")); + // $(".name-service").val(selectedTexts.join(", ")); + }); + + // quando selecionado ele habilita o campo de texto para editar o texto + $('.sobrescrever').change(function () { + var elements = document.getElementsByClassName('ads-name-individual'); + var package = document.getElementById('ads-name-package'); + var ads = document.getElementById('ads-name-individual'); + + if (!package.disabled) { + package.disabled = true; + } else { + package.disabled = false; + } + + if (!ads.disabled) { + ads.disabled = true; + } else { + ads.disabled = false; + } + + for (var i = 0; i < elements.length; i++) { + var element = elements[i]; + if (!element.disabled) { + element.disabled = true; + } else { + element.disabled = false; + } + } + + }); + +}); +//inicializa o select de serviços com os serviços da especialidade selecionada +$('#expertise-select-package').change(function () { + let expertiseId = $(this).val(); + let url = 'minha-conta/profissional/especialidades/' + expertiseId + '/servicos'; + + $.get(url, function (data) { + let options = ''; + data.forEach(function (service) { + options += ''; + }); + $('#service-select-package').html(options); + $('#service-select-package').formSelect(); + }); +}); + +//inicializa o select de serviços com os serviços da especialidade selecionada +$('#expertise-select-combined').change(function () { + let expertiseId = $(this).val(); + let url = 'minha-conta/profissional/especialidades/' + expertiseId + '/servicos'; + + $.get(url, function (data) { + let options = ''; + data.forEach(function (service) { + options += ''; + }); + $('#mySelect').html(options); + $('#mySelect').formSelect(); + }); +}); + +// remove a mascara no campo de valor, para quando enviar pro controller não dar erro de conversão +function RemoveMaskIndividual() { + str = $("#ads-price-individual").val(); + str = str.replace(/[^\d]+/g,""); + $("#price-service-individual").val(str); +} + +function RemoveMaskCombined() { + str = $("#ads-price-combined").val(); + str = str.replace(/[^\d]+/g,""); + $("#price-service-combined").val(str); +} + +function RemoveMaskPackage() { + str = $("#ads-price-package").val(); + str = str.replace(/[^\d]+/g,""); + $("#price-service-package").val(str); +} + +function mostrarSelecionados() { + var select = document.getElementById("mySelect"); + var selecionados = []; + var selecionadosIds = []; + + // Adiciona os valores selecionados como itens de lista + for (var i = 1; i < select.options.length; i++) { + if (select.options[i].selected && select.options[i].value !== "") { + selecionados.push(select.options[i].text); + selecionadosIds.push(select.options[i].value); + } + } + var resultadoDiv = document.getElementById("descriptionarray"); + resultadoDiv.value = selecionados.join(", "); + + var resultadoDiv2 = document.getElementById("descriptions"); + resultadoDiv2.value = selecionadosIds.join(", "); + + var resultadoDiv1 = document.getElementById("description"); + resultadoDiv1.value = selecionados.join(", "); +} + diff --git a/src/main/webapp/assets/resources/scripts/mp-payment.js b/src/main/webapp/assets/resources/scripts/mp-payment.js new file mode 100644 index 00000000..7aa0b4f1 --- /dev/null +++ b/src/main/webapp/assets/resources/scripts/mp-payment.js @@ -0,0 +1,143 @@ +function showPayment(jobRequestId) { + + if ($(".brick-payment").is(":hidden")) { + $('.brick-payment').fadeIn(); + $('.brick-status').fadeIn(); + + } + else{ + $('.brick-payment').fadeOut(); + $('.brick-status').fadeOut(); + return; + } + + const renderPaymentBrick = async (bricksBuilder) => { + const settings = { + initialization: { + amount: 0.5, + }, + customization: { + paymentMethods: { + ticket: "all", + bankTransfer: "all", + creditCard: "all", + debitCard: "all", + mercadoPago: "all", + }, + }, + callbacks: { + onReady: () => {}, + onSubmit: ({ + selectedPaymentMethod, + formData + }) => { + console.log(jobRequestId) + // callback chamado ao clicar no botão de submissão dos dados + return new Promise((resolve, reject) => { + fetch("minha-conta/cliente/pagamento", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(formData), + }) + .then(response => { + if (!response.ok) { + return response.json().then(responseBody => { + throw new Error(responseBody.message); + }); + } + + return response.json(); + }) + .then((response) => { + const paymentId = response.data.id; + renderStatusScreenBrick(bricksBuilder, paymentId); + // sendPaymentVoucher(paymentId); + paymentJobRequest(paymentId, jobRequestId); + resolve(); + }) + .catch((error) => { + swal({ + title: "Opss", + text: error.message, + icon: "error", + }); + reject(); + }); + }); + }, + onError: (error) => { + console.error(error); + }, + }, + }; + + bricksBuilder.create( + "payment", + "paymentBrick_container", + settings + ) + .then(paymentBrickController => { + + }) + .catch(error => { + console.error(error); + }); + }; + + renderPaymentBrick(bricksBuilder); +} + + +const renderStatusScreenBrick = async (bricksBuilder, paymentId) => { + const settings = { + initialization: { + paymentId: paymentId, + }, + callbacks: { + onReady: () => { + /* + Callback chamado quando o Brick estiver pronto. + Aqui você pode ocultar loadings do seu site, por exemplo. + */ + }, + onError: (error) => { + console.error(error); + }, + }, + }; + + window.statusScreenBrickController = await bricksBuilder.create( + 'statusScreen', + 'statusScreenBrick_container', + settings, + ); +}; + +function paymentJobRequest(paymentId, jobRequestId) { + const URL = "/servicebook/minha-conta/cliente/pagamento/jobRequest"; + + var dto = { + jobRequestId: jobRequestId, + paymentId: 1, + }; + + fetch(URL, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify(dto), + }).then((response) => { + console.log(response) + if (response.ok) { + return response.json(); + } + }).then((data) => { + console.log('ID do item salvo:', data); + }).catch((error) => { + console.error('Erro ao processar a solicitação:', error); + alert("Houve um problema, não foi possível seguir."); + }); +} \ No newline at end of file diff --git a/src/main/webapp/assets/resources/scripts/search.js b/src/main/webapp/assets/resources/scripts/search.js new file mode 100644 index 00000000..4c172eae --- /dev/null +++ b/src/main/webapp/assets/resources/scripts/search.js @@ -0,0 +1,121 @@ +$(document).ready(function () { + if ($("#category-select").val() != '') { + selectCategory($("#category-select").val()) + } + + var element = $("#dto_expertise").val(); + + function selectCategory(categoryId) { + $.ajax({ + url: "especialidades/categoria/"+ categoryId, + type: "GET", + success: function (expertises) { + $("#expertise-select").empty(); + + //se o array for vazio, coloca o option que não há especialidades + if (expertises.length === 0){ + $('#expertise-select').prop("disabled", true); + $("#expertise-select").append(""); + } else + $('#expertise-select').removeAttr("disabled"); + $("#expertise-select").append(""); + + $.each(expertises, function (index, expertise) { + + if(expertise.id == element){ + $("#expertise-select").append(""); + }else { + $("#expertise-select").append(""); + } + + }); + $("#expertise-select").formSelect(); + } + }); + } + if ($("#expertise-select").val() != '') { + selectExpertise(element) + } + + var element_service = $("#dto_service").val(); + function selectExpertise(expertiseId) { + $.ajax({ + url: "servicos/especialidade/"+ expertiseId, + type: "GET", + success: function (services) { + + $("#service-select").empty(); + + //se o array for vazio, coloca o option que não há especialidades + if (services.length === 0) { + $('#service-select').prop("disabled", true); + $("#service-select").append(""); + } else + $('#service-select').removeAttr("disabled"); + $("#service-select").append(""); + + $.each(services, function (index, service) { + $("#service-select").append(""); + + if(service.id == element_service){ + $("#service-select").append(""); + }else { + $("#service-select").append(""); + } + + }); + $("#service-select").formSelect(); + } + }); + } + + // LISTA DE ESPECIALIDADE DE ACORDO COM A CATEGORIA + $("#category-select").change(function () { + let categoryId = $(this).val(); + $.ajax({ + url: "especialidades/categoria/"+ categoryId, + type: "GET", + success: function (expertises) { + console.log(expertises) + + $("#expertise-select").empty(); + + //se o array for vazio, coloca o option que não há especialidades + if (expertises.length === 0) + $("#expertise-select").append(""); + else + $("#expertise-select").append(""); + + $.each(expertises, function (index, expertise) { + $("#expertise-select").append(""); + }); + $("#expertise-select").formSelect(); + } + }); + }); + + // LISTA DE SERVIÇOS DE ACORDO COM A ESPECIALIDADE + $("#expertise-select").change(function () { + let expertiseId = $(this).val(); + $.ajax({ + url: "servicos/especialidade/"+ expertiseId, + type: "GET", + success: function (services) { + + $("#service-select").empty(); + + //se o array for vazio, coloca o option que não há especialidades + if (services.length === 0) + $("#service-select").append(""); + else + $("#service-select").append(""); + + $.each(services, function (index, service) { + $("#service-select").append(""); + + }); + $("#service-select").formSelect(); + } + }); + }); +}) \ No newline at end of file diff --git a/src/main/webapp/assets/resources/styles/professional/ads.css b/src/main/webapp/assets/resources/styles/professional/ads.css new file mode 100644 index 00000000..b6983d8f --- /dev/null +++ b/src/main/webapp/assets/resources/styles/professional/ads.css @@ -0,0 +1,80 @@ +.active-profission{ + border: #00b0ff 2px solid; + padding: 20px; +} +/*LABEL DOS CAMPOS*/ +.label-ads{ + /*margin-top: 5% !important;*/ + margin: 0 !important; + font-size: .75rem !important; +} + +/*MEUS ANUNCIOS*/ +.card .card-content{ + padding: 13px !important; +} +.label_price{ + /*background-color: #333333;*/ + background-color: #81C5F3; + font-weight: bold; + font-size: 1rem; + text-align: center; + padding: 5px; +} +.label_duration{ + /*background-color: #333333;*/ + background-color: #81C5F3; + font-weight: bold; + font-size: 1rem; + text-align: center; + padding: 5px; +} +.label_especialidade{ + background-color: #333333; + margin: 0; + color: white; + font-weight: bold; + text-align: center; +} + +.div_cards_services{ + margin: 10px 0 30px; +} + +.btn_view{ + /*float: right;*/ + float: right; + color: #1194e5 !important; + font-weight: bold; +} +/*.card{*/ +/* height: 100%;*/ +/*}*/ + +#show-service-combined{ + margin-top: 45px; +} +#add-service-combined{ + height: 3rem; + line-height: 3rem; + width: 100%; +} + +.texto-com-elipse { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + width: 200px; +} + +.ads-price-label{ + border: none !important; + color: black !important; +} + + +/*CADASTRO*/ +.div_text_section{ + margin: 5px 5px 0 !important; + font-weight: bold; +} diff --git a/src/main/webapp/assets/resources/styles/styles.css b/src/main/webapp/assets/resources/styles/styles.css index 36b27409..8f8aa3e0 100644 --- a/src/main/webapp/assets/resources/styles/styles.css +++ b/src/main/webapp/assets/resources/styles/styles.css @@ -658,3 +658,17 @@ textarea { .expertise-select-card:hover{ background-color: #4962B3; } + +.card-request1{ + color: white; + font-size: 130%; + padding: 15px; +} + +.spacing-standard-request{ + margin-top: 30px; +} + +.btn-view-request{ + width: 150px; +} \ No newline at end of file diff --git a/src/main/webapp/assets/resources/styles/visitor/visitor.css b/src/main/webapp/assets/resources/styles/visitor/visitor.css index 5c4a4ad2..d84ab4a5 100644 --- a/src/main/webapp/assets/resources/styles/visitor/visitor.css +++ b/src/main/webapp/assets/resources/styles/visitor/visitor.css @@ -56,6 +56,58 @@ font-weight: 400; } +/*cards da pesquisa*/ +.card .card-content{ + padding: 13px !important; +} +.label_price{ + /*background-color: #333333;*/ + background-color: #53b1ed; + font-weight: bold; + font-size: 1rem; + text-align: center; + padding: 5px; +} +.label_duration{ + /*background-color: #333333;*/ + background-color: #53b1ed; + font-weight: bold; + font-size: 1rem; + text-align: center; + padding: 5px; +} + +.div_cards_services{ + margin: 10px 0 30px; +} + +.btn_view{ + /*float: right;*/ + float: right; + color: #1194e5 !important; + font-weight: bold; +} +.button-profile{ + font-size: .8rem !important; + margin-top: 30px; +} +.card-name-service{ + padding: 0; + margin-top: 0 !important; + margin: 0 10px 20px; +} +.card-name-expertise{ + background-color: #53b1ed; + margin: 0; +} +.avatar-expertise{ + width: 60px; + margin: 0 10px; +} +.span-name{ + position: absolute; + top: 10%; +} \ No newline at end of file