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..cf7e2542 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,18 @@ 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 com.mercadopago.client.common.AddressRequest; +import com.mercadopago.client.common.IdentificationRequest; +import com.mercadopago.client.common.PhoneRequest; +import com.mercadopago.client.preference.*; +import com.mercadopago.resources.preference.Preference; +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 +40,20 @@ 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.math.BigDecimal; +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; +import com.mercadopago.MercadoPagoConfig; @RequestMapping("/minha-conta/cliente") @Controller @@ -104,7 +122,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 @@ -222,6 +265,106 @@ public ModelAndView showDetailsRequest(@PathVariable Optional id) throws E }) .collect(Collectors.toList()); + MercadoPagoConfig.setAccessToken("TEST-2738533774159236-052518-f4e09de99516f8d7b2adb21186313d1b-494777183"); + PreferenceClient client = new PreferenceClient(); + + PreferenceItemRequest itemRequest = + PreferenceItemRequest.builder() + .id("1234") + .title("Dummy Title") + .description("Dummy description") + .pictureUrl("http://www.myapp.com/myimage.jpg") + .categoryId("car_electronics") + .quantity(1) + .currencyId("BRL") + .unitPrice(new BigDecimal("10")) + .build(); + + List items = new ArrayList<>(); + items.add(itemRequest); + + PreferenceFreeMethodRequest freeMethod = + PreferenceFreeMethodRequest.builder() + .id(1L).build(); + List freeMethodList = new ArrayList<>(); + freeMethodList.add(freeMethod); + + List excludedPaymentTypes = new ArrayList<>(); + excludedPaymentTypes.add(PreferencePaymentTypeRequest.builder().id("ticket").build()); + + List excludedPaymentMethods = new ArrayList<>(); + excludedPaymentMethods.add(PreferencePaymentMethodRequest.builder().id("").build()); + + PreferenceRequest preferenceRequest = PreferenceRequest.builder() + .backUrls( + PreferenceBackUrlsRequest.builder() + .success("http://test.com/success") + .failure("http://test.com/failure") + .pending("http://test.com/pending") + .build()) + .differentialPricing( + PreferenceDifferentialPricingRequest.builder() + .id(1L) + .build()) + .expires(false) + .items(items) + .marketplaceFee(new BigDecimal("0")) + .payer( + PreferencePayerRequest.builder() + .name("Test") + .surname("User") + .email("your_test_email@example.com") + .phone(PhoneRequest.builder().areaCode("11").number("4444-4444").build()) + .identification( + IdentificationRequest.builder().type("CPF").number("19119119100").build()) + .address( + AddressRequest.builder() + .zipCode("06233200") + .streetName("Street") + .streetNumber("123") + .build()) + .build()) + .additionalInfo("Discount: 12.00") + .autoReturn("all") + .binaryMode(true) + .externalReference("1643827245") + .marketplace("marketplace") + .notificationUrl("http://notificationurl.com") + .operationType("regular_payment") + .paymentMethods( + PreferencePaymentMethodsRequest.builder() + .defaultPaymentMethodId("master") + .excludedPaymentTypes(excludedPaymentTypes) + .excludedPaymentMethods(excludedPaymentMethods) + .installments(5) + .defaultInstallments(1) + .build()) + .shipments( + PreferenceShipmentsRequest.builder() + .mode("custom") + .localPickup(false) + .defaultShippingMethod(null) + .freeMethods(freeMethodList) + .cost(BigDecimal.TEN) + .freeShipping(false) + .dimensions("10x10x20,500") + .receiverAddress( + PreferenceReceiverAddressRequest.builder() + .zipCode("06000000") + .streetNumber("123") + .streetName("Street") + .floor("12") + .apartment("120A") + .build()) + .build()) + .statementDescriptor("Test Store") + .build(); + + Preference preference = client.create(preferenceRequest); + + + System.out.println("AAAAAAA"); + System.out.println(preference.getClientId()); mv.addObject("candidates", jobCandidatesDTOs); mv.addObject("expertise", expertiseDTO); mv.addObject("jobRequest", jobDTO); @@ -273,7 +416,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 +907,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..43bec1a8 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; @@ -115,15 +116,29 @@ public int getValue(){ @GetMapping @PermitAll public String showWizard(@RequestParam(value = "passo", required = false, defaultValue = "1") Long step, + @RequestParam(value = "especialidade", required = false, defaultValue = "0") Long expertiseId, HttpSession httpSession, Model model) throws Exception { log.debug("Mostrando o passo {}", step); 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); + if(expertiseId != 0){ + JobRequestDTO sessionDTO = wizardSessionUtil.getWizardState(httpSession, JobRequestDTO.class, WizardSessionUtil.KEY_WIZARD_JOB_REQUEST); + sessionDTO.setExpertiseId(expertiseId); + } + if(step == 1L){ List expertise = expertiseService.findAll(); List expertiseDTOs = expertise.stream() @@ -173,7 +188,6 @@ public String saveFormRequestedJob(HttpSession httpSession, @Validated(JobReques @PermitAll public String saveFormDateJob(HttpSession httpSession, @Validated(JobRequestDTO.RequestExpirationGroupValidation.class) JobRequestDTO dto, BindingResult errors, RedirectAttributes redirectAttributes, Model model) throws Exception { - if(errors.hasErrors()){ model.addAttribute("dto", dto); model.addAttribute("errors", errors.getAllErrors()); @@ -216,7 +230,7 @@ public String saveFormDateJob(HttpSession httpSession, @Validated(JobRequestDTO. } sessionDTO.setDateTarget(DateUtil.getToday()); log.debug("Passo 2 {}", sessionDTO); - return "redirect:/requisicoes?passo=3"; + return "redirect:/requisicoes?passo=4"; } @PostMapping("/passo-3") @@ -291,7 +305,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=7"; } else { return "redirect:/requisicoes/passo=5"; } @@ -336,7 +350,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 +470,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..bac1a068 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,59 @@ 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()); + + Page professionalsByExpertise = individualService.findDistinctByExpertiseAndCategoryPagination(expertise.get(), page, size); + + Page listProfessionals = individualService.listByExpertiseAndCategory(expertise.get(), category.get(), page, size); + + List professionalSearchItemDTOS2 = professionalsByExpertise.stream() + .map(s -> individualMapper.toSearchItemDto(s, individualService.getExpertises(s))) + .collect(Collectors.toList()); + + List professionals1 = individualService.findAllIndividualsAutonomosByService(expertise.get().getId(), page, size); + + List professionalSearchItemDTOS1 = professionals1.stream() + .map(s -> individualMapper.toSearchItemDto(s, individualService.getExpertises(s))) + .collect(Collectors.toList()); + + PaginationDTO paginationDTO = paginationUtil.getPaginationDTO(professionalServiceOfferings, "/profissionais/busca?termo-da-busca=" + searchService); + + mv.addObject("professionals", professionalSearchItemDTOS2); + 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); + mv.addObject("count_results", professionalServiceOfferingDTOS.size()); + } return mv; } @@ -150,6 +208,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 +219,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 +236,71 @@ 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()) { + continue; + } + + //transforma para DTO + List professionalServiceOfferingsDTO = professionalServiceOfferings.stream() + .map(service -> professionalServiceOfferingMapper.toDTO(service)) + .collect(Collectors.toList()); + + servicesByExpertise.put(pe, professionalServiceOfferingsDTO); + } + + ModelAndView mv = new ModelAndView("visitor/professional-details"); + mv.addObject("professional", professionalDTO); + mv.addObject("professionalExpertises", expertisesDTO); + mv.addObject("logged", oClientAuthenticated.isPresent()); + mv.addObject("servicesByExpertise", servicesByExpertise); + + //se o cliente está logado, mostra se ele segue o profissional + if (oClientAuthenticated.isPresent()) { + List follows = followsService.findFollowProfessionalClient(oProfessional.get(), oClientAuthenticated.get()); + boolean isFollow = !follows.isEmpty(); + UserDTO clientDTO = userMapper.toDto(oClientAuthenticated.get()); + mv.addObject("isFollow", isFollow); + mv.addObject("client", clientDTO); + } + return mv; + } + + @GetMapping("/detalhes/{id}/servico/{service_id}") + @PermitAll + protected ModelAndView showProfessionalDetailsAndServiceToVisitors(@PathVariable("id") Long id, @PathVariable("service_id") Long service_id) throws Exception { + + Optional oProfessional = userService.findById(id); + + if (!oProfessional.isPresent()) { + throw new EntityNotFoundException("Profissional não encontrado."); + } + + Optional oService = serviceService.findById(service_id); + + if (!oService.isPresent()) { + throw new EntityNotFoundException("Serviço não encontrado."); + } + + //cliente autenticado, caso esteja logado + Optional oClientAuthenticated = (userService.findByEmail(authentication.getEmail())); + + //profissional requisitado + UserDTO professionalDTO = userMapper.toDto(oProfessional.get()); + + //especialidades do profissional requisitado + List expertisesDTO = userService.getExpertiseDTOs(oProfessional.get()); + + List professionalExpertises = professionalExpertiseService.findByProfessional(oProfessional.get()); + + //serviços por especialidade + Map> servicesByExpertise = new HashMap<>(); + for (ProfessionalExpertise pe : professionalExpertises) { List professionalServiceOfferings = professionalServiceOfferingService.findProfessionalServiceOfferingByUserAndExpertise(oProfessional.get().getId(), pe.getExpertise().getId()); - if(professionalServiceOfferings.isEmpty()){ + if (professionalServiceOfferings.isEmpty()) { continue; } @@ -197,9 +317,10 @@ protected ModelAndView showProfessionalDetailsToVisitors(@PathVariable("id") Lon mv.addObject("professionalExpertises", expertisesDTO); mv.addObject("logged", oClientAuthenticated.isPresent()); mv.addObject("servicesByExpertise", servicesByExpertise); + mv.addObject("service", oService.get()); //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/JobContractedFullDTO.java b/src/main/java/br/edu/utfpr/servicebook/model/dto/JobContractedFullDTO.java index 7293c57f..4c3151ba 100644 --- a/src/main/java/br/edu/utfpr/servicebook/model/dto/JobContractedFullDTO.java +++ b/src/main/java/br/edu/utfpr/servicebook/model/dto/JobContractedFullDTO.java @@ -4,6 +4,8 @@ import lombok.Data; import lombok.NoArgsConstructor; +import java.time.LocalDate; + @Data @NoArgsConstructor @AllArgsConstructor @@ -13,5 +15,6 @@ public class JobContractedFullDTO { private String comments; private int rating; private JobRequestFullDTO jobRequest; + private String todoDate; } diff --git a/src/main/java/br/edu/utfpr/servicebook/model/dto/JobRequestDetailsDTO.java b/src/main/java/br/edu/utfpr/servicebook/model/dto/JobRequestDetailsDTO.java index 08de75f4..29c22e13 100644 --- a/src/main/java/br/edu/utfpr/servicebook/model/dto/JobRequestDetailsDTO.java +++ b/src/main/java/br/edu/utfpr/servicebook/model/dto/JobRequestDetailsDTO.java @@ -3,6 +3,7 @@ import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; +import org.springframework.web.multipart.MultipartFile; import java.io.Serializable; @@ -21,5 +22,6 @@ public class JobRequestDetailsDTO implements Serializable { private Long totalCandidates; private String textualDate; private Long amountOfCandidates; + private MultipartFile imageFile; } diff --git a/src/main/java/br/edu/utfpr/servicebook/model/dto/JobRequestFullDTO.java b/src/main/java/br/edu/utfpr/servicebook/model/dto/JobRequestFullDTO.java index 9d5bae45..ba3495de 100644 --- a/src/main/java/br/edu/utfpr/servicebook/model/dto/JobRequestFullDTO.java +++ b/src/main/java/br/edu/utfpr/servicebook/model/dto/JobRequestFullDTO.java @@ -1,10 +1,15 @@ package br.edu.utfpr.servicebook.model.dto; +import br.edu.utfpr.servicebook.model.entity.JobImages; +import br.edu.utfpr.servicebook.model.entity.User; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; +import org.springframework.web.multipart.MultipartFile; import java.io.Serializable; +import java.util.HashSet; +import java.util.Set; @Data @NoArgsConstructor @@ -21,7 +26,11 @@ public class JobRequestFullDTO implements Serializable { private Long totalCandidates; private String textualDate; private Long amountOfCandidates; + private User user; public String status; + private MultipartFile imageFile; + private Set jobImages = new HashSet<>(); + } 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/ProfessionalSearchItemDTO.java b/src/main/java/br/edu/utfpr/servicebook/model/dto/ProfessionalSearchItemDTO.java index 48eada24..27c502e7 100644 --- a/src/main/java/br/edu/utfpr/servicebook/model/dto/ProfessionalSearchItemDTO.java +++ b/src/main/java/br/edu/utfpr/servicebook/model/dto/ProfessionalSearchItemDTO.java @@ -1,5 +1,7 @@ package br.edu.utfpr.servicebook.model.dto; +import br.edu.utfpr.servicebook.model.entity.Expertise; +import br.edu.utfpr.servicebook.model.entity.Individual; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @@ -20,10 +22,11 @@ public class ProfessionalSearchItemDTO extends UserDTO { private int rating; private int denounceAmount; - public String getOnlyNumbersFromPhone() { return getPhoneNumber().replaceAll("[^0-9]", ""); } public List expertises; + + public Expertise expertise; } \ No newline at end of file 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/JobRequest.java b/src/main/java/br/edu/utfpr/servicebook/model/entity/JobRequest.java index 11a73c12..356fe810 100644 --- a/src/main/java/br/edu/utfpr/servicebook/model/entity/JobRequest.java +++ b/src/main/java/br/edu/utfpr/servicebook/model/entity/JobRequest.java @@ -6,6 +6,7 @@ import javax.persistence.*; +import br.edu.utfpr.servicebook.model.dto.ClientMinDTO; import lombok.*; @Data @@ -39,7 +40,7 @@ public enum Status { @ManyToOne @JoinColumn(name = "client_id") private User user; - + @ManyToOne @JoinColumn(name = "expertise_id") private Expertise expertise; 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..2757a111 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 @@ -13,7 +13,7 @@ * Ele pode ter várias customizações para um mesmo serviço cadastrado pelo Administrador. */ @Data -@Table(name = "professional_service_offerings") + @Table(name = "professional_service_offerings") @NoArgsConstructor @Entity public class ProfessionalServiceOffering { @@ -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/IndividualMapper.java b/src/main/java/br/edu/utfpr/servicebook/model/mapper/IndividualMapper.java index 36cda32e..298cda4b 100644 --- a/src/main/java/br/edu/utfpr/servicebook/model/mapper/IndividualMapper.java +++ b/src/main/java/br/edu/utfpr/servicebook/model/mapper/IndividualMapper.java @@ -2,6 +2,7 @@ import br.edu.utfpr.servicebook.model.dto.*; +import br.edu.utfpr.servicebook.model.entity.Expertise; import br.edu.utfpr.servicebook.model.entity.Individual; import br.edu.utfpr.servicebook.util.UserTemplateInfo; import org.modelmapper.ModelMapper; diff --git a/src/main/java/br/edu/utfpr/servicebook/model/mapper/JobContractedMapper.java b/src/main/java/br/edu/utfpr/servicebook/model/mapper/JobContractedMapper.java index e3e6d201..12c55d64 100644 --- a/src/main/java/br/edu/utfpr/servicebook/model/mapper/JobContractedMapper.java +++ b/src/main/java/br/edu/utfpr/servicebook/model/mapper/JobContractedMapper.java @@ -8,12 +8,14 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; +import java.time.format.DateTimeFormatter; import java.util.Optional; @Component public class JobContractedMapper { @Autowired private ModelMapper mapper; + private DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("dd/MM/yyyy"); public JobContractedDTO toDto(JobContracted entity) { JobContractedDTO dto = mapper.map(entity, JobContractedDTO.class); @@ -40,7 +42,11 @@ public JobContractedFullDTO toFullDto(JobContracted entity, Optional total JobContractedFullDTO dto = mapper.map(entity, JobContractedFullDTO.class); dto.getJobRequest().setTotalCandidates(totalCandidates.get()); dto.getJobRequest().setTextualDate(DateUtil.getTextualDate((entity.getJobRequest().getDateTarget()))); - + dto.getJobRequest().setIndividual(dto.getJobRequest().getIndividual()); + if(entity.getJobRequest().getDateCreated() != null) { + dto.getJobRequest().setDateCreated(this.dateTimeFormatter.format(entity.getJobRequest().getDateCreated())); + } + dto.setTodoDate(this.dateTimeFormatter.format(entity.getTodoDate())); return dto; } 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..d9747ac3 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 @@ -1,10 +1,7 @@ package br.edu.utfpr.servicebook.model.mapper; -import br.edu.utfpr.servicebook.model.dto.JobRequestDTO; -import br.edu.utfpr.servicebook.model.dto.JobRequestDetailsDTO; -import br.edu.utfpr.servicebook.model.dto.JobRequestFullDTO; -import br.edu.utfpr.servicebook.model.dto.JobRequestMinDTO; +import br.edu.utfpr.servicebook.model.dto.*; import br.edu.utfpr.servicebook.model.entity.JobRequest; import br.edu.utfpr.servicebook.util.DateUtil; import org.modelmapper.ModelMapper; @@ -25,6 +22,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 +47,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())); @@ -68,6 +68,9 @@ public JobRequestFullDTO toFullDto(JobRequest entity, Optional totalCandid dto.setDateTarget(this.dateTimeFormatter.format(entity.getDateTarget())); dto.setTextualDate(DateUtil.getTextualDate((entity.getDateTarget()))); + dto.setUser(entity.getUser()); + dto.setJobImages(entity.getJobImages()); + return dto; } 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..409c7c50 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,11 @@ package br.edu.utfpr.servicebook.model.repository; +import br.edu.utfpr.servicebook.model.dto.IndividualDTO; +import br.edu.utfpr.servicebook.model.dto.ProfessionalSearchItemDTO; +import br.edu.utfpr.servicebook.model.entity.Category; +import br.edu.utfpr.servicebook.model.entity.Expertise; 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 +58,32 @@ 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); + + @Query("select distinct p from Individual p left join ProfessionalExpertise pe on p.id = pe.professional.id " + + " left join Expertise ex on pe.expertise.id = ex.id "+ + "where pe.expertise = :expertiseId ") + Page findDistinctByExpertiseAndCategoryPagination( + Expertise expertiseId, + Pageable pageable); + + @Query("select distinct ex from Individual p left join ProfessionalExpertise pe on p.id = pe.professional.id " + + " left join Expertise ex on pe.expertise.id = ex.id "+ + "where pe.expertise = :expertiseId or pe.expertise.category = :categoryId") + Page listByExpertiseAndCategory( + Expertise expertiseId, + Category categoryId, + 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..a201c701 100644 --- a/src/main/java/br/edu/utfpr/servicebook/service/IndividualService.java +++ b/src/main/java/br/edu/utfpr/servicebook/service/IndividualService.java @@ -1,6 +1,8 @@ package br.edu.utfpr.servicebook.service; import br.edu.utfpr.servicebook.model.dto.ExpertiseDTO; +import br.edu.utfpr.servicebook.model.dto.IndividualDTO; +import br.edu.utfpr.servicebook.model.dto.ProfessionalSearchItemDTO; import br.edu.utfpr.servicebook.model.entity.*; import br.edu.utfpr.servicebook.model.mapper.ExpertiseMapper; import br.edu.utfpr.servicebook.model.repository.CompanyRepository; @@ -129,11 +131,30 @@ 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) { professionalExpertiseRepository.save(professionalExpertise); companyRepository.save(company); } + + public Page findDistinctByExpertiseAndCategoryPagination(Expertise expertiseId, Integer page, Integer size){ + PageRequest pageRequest = PageRequest.of(page - 1, size); + return this.individualRepository.findDistinctByExpertiseAndCategoryPagination(expertiseId, pageRequest); + } + + public Page listByExpertiseAndCategory(Expertise expertiseId, Category categoryId, Integer page, Integer size){ + PageRequest pageRequest = PageRequest.of(page - 1, size); + return this.individualRepository.listByExpertiseAndCategory(expertiseId, categoryId, pageRequest); + } + } \ No newline at end of file diff --git a/src/main/java/br/edu/utfpr/servicebook/service/JobRequestService.java b/src/main/java/br/edu/utfpr/servicebook/service/JobRequestService.java index 84fdcead..286ba396 100644 --- a/src/main/java/br/edu/utfpr/servicebook/service/JobRequestService.java +++ b/src/main/java/br/edu/utfpr/servicebook/service/JobRequestService.java @@ -1,6 +1,7 @@ package br.edu.utfpr.servicebook.service; import br.edu.utfpr.servicebook.model.entity.Expertise; +import br.edu.utfpr.servicebook.model.entity.JobImages; import br.edu.utfpr.servicebook.model.entity.JobRequest; import br.edu.utfpr.servicebook.model.entity.User; import br.edu.utfpr.servicebook.model.repository.JobRequestRepository; @@ -13,8 +14,10 @@ import java.sql.Date; import java.time.LocalDate; +import java.util.Collections; import java.util.List; import java.util.Optional; +import java.util.Set; @Slf4j @Service @@ -125,4 +128,9 @@ public long countByExpertise(Expertise expertise){ public long countByStatusAndExpertise(JobRequest.Status status, Expertise expertise){ return this.jobRequestRepository.countByStatusAndExpertise(status, expertise); } + + public Set getJobImagesById(Long jobId) { + Optional optionalJobRequest = jobRequestRepository.findById(jobId); + return optionalJobRequest.map(JobRequest::getJobImages).orElse(Collections.emptySet()); + } } \ No newline at end of file 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..c2d8f25e --- /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("TEST-2738533774159236-052518-f4e09de99516f8d7b2adb21186313d1b-494777183"); + + 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/banner.tag b/src/main/webapp/WEB-INF/tags/banner.tag index edcd0049..84b343e8 100644 --- a/src/main/webapp/WEB-INF/tags/banner.tag +++ b/src/main/webapp/WEB-INF/tags/banner.tag @@ -13,7 +13,7 @@ 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-client.tag b/src/main/webapp/WEB-INF/tags/navbar-client.tag index dbb0b2b3..c8128367 100644 --- a/src/main/webapp/WEB-INF/tags/navbar-client.tag +++ b/src/main/webapp/WEB-INF/tags/navbar-client.tag @@ -10,9 +10,6 @@
",{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)}),-1' + service.name + ''; + }); + $('#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..6c56199c --- /dev/null +++ b/src/main/webapp/assets/resources/scripts/mp-payment.js @@ -0,0 +1,138 @@ +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, + preferenceId: "2738533774159236", + }, + 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 + ) + }; + + 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..55ee916b --- /dev/null +++ b/src/main/webapp/assets/resources/scripts/search.js @@ -0,0 +1,148 @@ +$(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(); + } + }); + }); + + var selectedValue = $('#service-select').val(); + + if (selectedValue) { + $("#hide_simple_button").prop("disabled", false); + $("#add_ads").show(); + } else { + $("#hide_simple_button").prop("disabled", true); + $("#add_ads").hide(); + } + + $("#service-select").on("change", function() { + var selectedValue = $('#service-select').val(); + + if (selectedValue) { + $("#hide_simple_button").prop("disabled", false); + $("#add_ads").show(); + } else { + $("#hide_simple_button").prop("disabled", true); + $("#add_ads").hide(); + } + + }); + +}) \ No newline at end of file diff --git a/src/main/webapp/assets/resources/styles/admin/admin.css b/src/main/webapp/assets/resources/styles/admin/admin.css index 06a14c38..5dc29f29 100644 --- a/src/main/webapp/assets/resources/styles/admin/admin.css +++ b/src/main/webapp/assets/resources/styles/admin/admin.css @@ -6,6 +6,7 @@ .input-field { padding: 0 !important; + height: auto !important; } .input-field .select-wrapper input { diff --git a/src/main/webapp/assets/resources/styles/banner-hidden.css b/src/main/webapp/assets/resources/styles/banner-hidden.css new file mode 100644 index 00000000..09603c9d --- /dev/null +++ b/src/main/webapp/assets/resources/styles/banner-hidden.css @@ -0,0 +1,34 @@ +.city-name { + width: 100%; + padding: 10px 0; + /*background-color: #f5f5f5;*/ + color: #0d47a1; +} + +.cityNameContent { + display: flex; + justify-content: start; +} +.expanded { + transform: rotate(180deg); +} + +#painel { + padding: 0; +} + +#toggle-city-id { + cursor: pointer; + margin-left: 1.2em; + margin-top: 5px; + margin-bottom: 0; +} + +@media screen and (max-width: 600px) { + .cityNameContent { + justify-content: space-between; + } +} +#city-panel{ + margin: 0 !important; +} \ No newline at end of file diff --git a/src/main/webapp/assets/resources/styles/client/client.css b/src/main/webapp/assets/resources/styles/client/client.css index e69de29b..a6f73b24 100644 --- a/src/main/webapp/assets/resources/styles/client/client.css +++ b/src/main/webapp/assets/resources/styles/client/client.css @@ -0,0 +1,106 @@ +.col-image-job-request{ + background-color: #E6E6E6; + display: flex; + justify-content: center; + align-items: center; + /*margin-top: 15px;*/ +} + +.icone-default{ + text-align: center; +} + +.icone-default i{ + color: #B8B8B8; + font-size: 10rem; + text-align: center; +} + +.progress{ + margin: 10px 0 0!important; + height: 25px !important; + background-color: #6700EB !important; +} + +.btn-view-request{ + font-size: .8rem !important; + padding: 0 !important; + width: 100px !important; + margin: 5px 0 !important; + float: right; +} + +.card-progress{ + padding: 0 !important; + margin: 0!important; +} + +.truncate{ + margin: 0 !important; + font-size: .9rem; +} + +.qtd_candidates { + position: absolute; + right: 10px; + top: 50%; + transform: translateY(-50%); +} + +.card-footer { + position: relative; + height: 30px; +} + +.determinate { + height: 100%; + background-color: #65AFEB !important; +} + +.progress-text { + position: absolute; + right: 10px; + top: 50%; + transform: translateY(-50%); + white-space: nowrap; + color: black; + font-weight: bold; +} + +.card-image{ + /*display: flex !important;*/ + /*justify-content: center !important;*/ + /*align-items: center !important;*/ +} + +.image-professional{ + margin-top: 15px; + width: 40% !important; +} + +.card-link{ + color: black; +} +.description-job-card{ + font-size: .8rem; +} + +.label_especialidade{ + background-color: #333333; + margin: 0 !important; + color: white; + font-weight: bold; + text-align: center; +} + +#follow-button, #unfollow-button{ + border-radius: 10px; +} + +.check-circle-candidate{ + margin-top: 10px !important; +} + +.job-details-professional-name{ + font-size: 1.5rem; +} \ No newline at end of file diff --git a/src/main/webapp/assets/resources/styles/colors.css b/src/main/webapp/assets/resources/styles/colors.css index e0244fba..9642d940 100644 --- a/src/main/webapp/assets/resources/styles/colors.css +++ b/src/main/webapp/assets/resources/styles/colors.css @@ -26,6 +26,10 @@ background-color: #81c5f3 !important; } +.primary-background-color-light{ + background-color: rgba(191, 222, 255, 0.8) !important; +} + .secondary-background-color{ background-color: rgb(51, 51, 51) !important; } 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..888d5d2c --- /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 !important; + 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/professional/professional.css b/src/main/webapp/assets/resources/styles/professional/professional.css index ab5d4e52..4868528e 100644 --- a/src/main/webapp/assets/resources/styles/professional/professional.css +++ b/src/main/webapp/assets/resources/styles/professional/professional.css @@ -1,4 +1,138 @@ .active-profission{ border: #00b0ff 2px solid; padding: 20px; +} + +.card-request1{ + color: white; + font-size: 130%; + padding: 15px; +} + +.contact-item-professional{ + font-size: 100%; +} + +.contact-item-professional i{ + font-size: 1.5rem !important; +} + +.col-image-job-request{ + background-color: #E6E6E6; + display: flex; + justify-content: center; + align-items: center; + /*margin-top: 15px;*/ +} + +.icone-default{ + text-align: center; +} + +.icone-default i{ + color: #B8B8B8; + font-size: 10rem; + text-align: center; +} + +.progress{ + margin: 10px 0 0!important; + height: 25px !important; + background-color: #6700EB !important; +} + +.btn-view-request{ + font-size: .8rem !important; + padding: 0 !important; + width: 100px !important; + margin: 5px 0 !important; + float: right; +} + +.card-progress{ + margin: 10px 0 0!important; + height: 25px !important; + background-color: #6700EB !important; +} + +.truncate{ + margin: 0 !important; + font-size: .9rem; +} + +.qtd_candidates { + position: absolute; + right: 10px; + top: 50%; + transform: translateY(-50%); +} + +.spacing-buttons{ + margin-bottom: 0 !important; +} + +.icon_default { + font-size: 1.5rem !important; + margin: 10px 0; + font-weight: bold !important; +} + +.my-button-flex{ + margin-top: 20px; +} + +.card-footer { + position: relative; + height: 30px; +} + +.determinate { + height: 100%; + background-color: #65AFEB !important; +} + +.progress-text { + position: absolute; + right: 10px; + top: 50%; + transform: translateY(-50%); + white-space: nowrap; + color: black; + font-weight: bold; +} + +.profilePicture{ + width: 50% !important; +} + +.card-image{ + /*display: flex !important;*/ + /*justify-content: center !important;*/ + /*align-items: center !important;*/ +} + +.image-professional{ + margin-top: 15px; + width: 40% !important; +} + +.card-link{ + color: black; +} +.description-job-card{ + font-size: .8rem; +} + +.label_especialidade{ + background-color: #333333; + margin: 0 !important; + color: white; + font-weight: bold; + text-align: center; +} + +.card .card-image .card-title{ + padding: 5px !important; + color: #0D47A1 !important; + font-size: .9rem !important; } \ No newline at end of file diff --git a/src/main/webapp/assets/resources/styles/styles.css b/src/main/webapp/assets/resources/styles/styles.css index 36b27409..573a31b0 100644 --- a/src/main/webapp/assets/resources/styles/styles.css +++ b/src/main/webapp/assets/resources/styles/styles.css @@ -166,7 +166,7 @@ input[type=range]::-webkit-slider-runnable-track{ .card-candidate { padding: 0; - border: #3f51b5 10px solid; + border: #3f51b5 2px solid; color: white; } @@ -183,10 +183,13 @@ input[type=range]::-webkit-slider-runnable-track{ .title-card-resquest{ height: 35px; - background-color: #1c2231; + background-color: #314564; + /*background-color: #1c2231;*/ + font-size: 140%; font-weight: 600; color: white; + border-radius: 5px; } .contact-item{ @@ -255,6 +258,10 @@ input[type=range]::-webkit-slider-runnable-track{ padding: 12px; } +.icons-area-request { + margin-top: 20px; +} + .header-verification { padding: 20px; padding-bottom: 0; @@ -658,3 +665,37 @@ 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; +} + +.contact-item-professional{ + font-size: 100%; +} + +.contact-item-professional i{ + font-size: 1.5rem !important; +} + +#follow-button, #unfollow-button{ + border-radius: 10px; +} + +.nav-form-especialidade{ + height: auto !important; +} + +.input-field{ + height: auto !important; +} \ 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..9a8b5547 100644 --- a/src/main/webapp/assets/resources/styles/visitor/visitor.css +++ b/src/main/webapp/assets/resources/styles/visitor/visitor.css @@ -56,6 +56,97 @@ 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; + margin: 0 !important; + padding: 5px; +} + +.label_duration{ + /*background-color: #333333;*/ + margin: 0 !important; + 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%; +} +.select-visitor .select-wrapper .select-dropdown{ + padding: 0 0 0 5px !important; + margin-right: 5px !important; +} + +.div-buttons{ + padding: 0 !important; + margin: 5px 8px; +} + +.input-field{ + margin-bottom: 0 !important; + height: auto !important; +} + +.card-image{ + display: flex !important; + justify-content: center !important; /* Centraliza horizontalmente */ + align-items: center !important; /* Centraliza verticalmente */ +} + +.image-professional{ + width: 50% !important; +} + +.card-link{ + color: black; +} +.description-job-card{ + font-size: .8rem; +} +/*.select-wrapper .select-dropdown {*/ +/* padding-left: 10px !important; !* Ajuste o valor conforme necessário *!*/ +/* font-size: .9rem !important; !* Opcional: ajuste o tamanho da fonte *!*/ +/*}*/