Initial commit

This commit is contained in:
Kayashov.SM
2025-03-12 17:54:16 +04:00
commit b6d8a3cebd
254 changed files with 29963 additions and 0 deletions

View File

@@ -0,0 +1,476 @@
package ru.kayashov.bar.service;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.hibernate.Session;
import org.hibernate.query.Query;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import ru.kayashov.bar.controller.dto.cocktail.CocktailFilterRequestDto;
import ru.kayashov.bar.controller.dto.cocktail.CocktailForListResponseDto;
import ru.kayashov.bar.controller.dto.cocktail.CocktailModalDto;
import ru.kayashov.bar.controller.dto.cocktail.CocktailSimpleResponseDto;
import ru.kayashov.bar.controller.dto.cocktail.ReceiptResponseDto;
import ru.kayashov.bar.mapper.CocktailMapper;
import ru.kayashov.bar.model.entity.AlcoholicEntity;
import ru.kayashov.bar.model.entity.BarEntity;
import ru.kayashov.bar.model.entity.BarIngredientStorage;
import ru.kayashov.bar.model.entity.BarResident;
import ru.kayashov.bar.model.entity.CategoryEntity;
import ru.kayashov.bar.model.entity.CocktailEntity;
import ru.kayashov.bar.model.entity.GlassEntity;
import ru.kayashov.bar.model.entity.IngredientEntity;
import ru.kayashov.bar.model.entity.Rating;
import ru.kayashov.bar.model.entity.ReceiptEntity;
import ru.kayashov.bar.model.entity.StopList;
import ru.kayashov.bar.model.entity.TagEntity;
import ru.kayashov.bar.model.entity.Visitor;
import ru.kayashov.bar.repository.AlcoholicRepository;
import ru.kayashov.bar.repository.CategoryRepository;
import ru.kayashov.bar.repository.CocktailRepository;
import ru.kayashov.bar.repository.GlassRepository;
import ru.kayashov.bar.repository.IngredientRepository;
import ru.kayashov.bar.repository.RatingRepository;
import ru.kayashov.bar.repository.ReceiptRepository;
import ru.kayashov.bar.repository.StopListRepository;
import ru.kayashov.bar.repository.TagRepository;
import ru.kayashov.bar.repository.VisitorsRepository;
import javax.persistence.EntityManager;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Join;
import javax.persistence.criteria.JoinType;
import javax.persistence.criteria.Order;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.persistence.criteria.Subquery;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
@Slf4j
@Service
@RequiredArgsConstructor
public class CocktailService {
@Value("${cocktail.photo.path}")
private String photoFolder;
private final StopListRepository stopListRepository;
private final CocktailMapper mapper;
private final CocktailRepository repository;
private final AlcoholicRepository alcoholicRepository;
private final CategoryRepository categoryRepository;
private final GlassRepository glassRepository;
private final TagRepository tagRepository;
private final ReceiptRepository receiptRepository;
private final IngredientRepository ingredientRepository;
private final VisitorsRepository visitorsRepository;
private final RatingRepository ratingRepository;
private final VisitorService visitorService;
private final EntityManager entityManager;
/**
* Вывод меню бара
*/
@Transactional
public List<CocktailForListResponseDto> getMenu(CocktailFilterRequestDto dto) {
return mapper.cocktailsToDtoList(criteria(dto), dto.getAll());
}
private List<CocktailEntity> criteria(CocktailFilterRequestDto dto) {
Visitor visitor = visitorService.getCurrentVisitor();
Session session = entityManager.unwrap(Session.class);
CriteriaBuilder cb = session.getCriteriaBuilder();
CriteriaQuery<CocktailEntity> criteriaQuery = cb.createQuery(CocktailEntity.class);
Root<CocktailEntity> root = criteriaQuery.from(CocktailEntity.class);
List<Predicate> predicates = new ArrayList<>();
if (!dto.getAll()) {
Long barId = visitor.getResidents().stream()
.filter(BarResident::getActive)
.map(BarResident::getBar)
.map(BarEntity::getId)
.toList()
.get(0);
List<Long> cocktailIds = getAllowedCocktailIds(barId);
Predicate pr = root.get("id").in(cocktailIds);
predicates.add(pr);
criteriaQuery.distinct(true);
List<Long> stopListIds = getStopListIds(visitor);
predicates.add(cb.not(root.get("id").in(stopListIds)));
}
if (!dto.getSearch().isEmpty()) {
String[] search = dto.getSearch().split(" ");
List<Predicate> in = new ArrayList<>();
Join<CocktailEntity, ReceiptEntity> receiptJoin = root.join("receipt", JoinType.LEFT);
for (String s : search) {
in.add(cb.like(cb.lower(root.get("name")), "%" + s.toLowerCase() + "%"));
in.add(cb.like(cb.lower(receiptJoin.get("ingredient").get("name")), "%" + s.toLowerCase() + "%"));
}
predicates.add(cb.or(in.toArray(new Predicate[0])));
}
if (dto.getOnlyFavourite()) {
List<Long> favouriteCocktailsId = visitor.getRating().stream()
.filter(Rating::isFavorite)
.map(Rating::getCocktail)
.map(CocktailEntity::getId)
.toList();
predicates.add(root.get("id").in(favouriteCocktailsId));
}
if (dto.getGlass() != null && !dto.getGlass().isEmpty()) {
predicates.add(root.get("glassEntity").get("name").in(dto.getGlass()));
}
if (dto.getCategory() != null && !dto.getCategory().isEmpty()) {
predicates.add(root.get("categoryEntity").get("name").in(dto.getCategory()));
}
if (dto.getAlcohol() != null && !dto.getAlcohol().isEmpty()) {
predicates.add(root.get("alcoholicEntity").get("name").in(dto.getAlcohol()));
}
if (!dto.getTags().isEmpty()) {
Join<CocktailEntity, TagEntity> tagJoin = root.join("tags", JoinType.LEFT);
predicates.add(tagJoin.get("name").in(dto.getTags()));
}
if (dto.getInMenu() != null) {
List<Long> stopListIds = getStopListIds(visitor);
switch (dto.getInMenu()) {
case "Есть в меню" -> predicates.add(cb.not(root.get("id").in(stopListIds)));
case "Нет в меню" -> predicates.add(root.get("id").in(stopListIds));
}
}
if(dto.getICount() != null) {
log.info("iii");
}
//
// if (!dto.getSortField().equals("name") || !dto.getSortOrder().equals("asc")) {
// cb.asc(root.get("name"));
//// query.orderBy(cb.asc(root.get("name").get(dto.getSortField())));
// } else {
// criteriaQuery.orderBy(cb.asc(root.get("name")));
// }
//todo: доделать другие виды сортировки
Order order;
switch (dto.getSort()) {
case NAME_ASC -> order = cb.asc(root.get("name"));
case NAME_DESC -> order = cb.desc(root.get("name"));
default -> order = cb.asc(root.get("name"));
}
criteriaQuery.where(predicates.toArray(new Predicate[0]))
.orderBy(order);
Query<CocktailEntity> query = session.createQuery(criteriaQuery);
query.setFirstResult(dto.getPage() * dto.getSize());
query.setMaxResults(dto.getSize());
List<CocktailEntity> cocktailEntities = query.getResultList();
log.info("Найдено {} коктейлей", cocktailEntities.size());
// return Collections.emptyList();
return cocktailEntities;
}
private List<Long> getStopListIds(Visitor visitor) {
return visitor.getResidents()
.stream()
.filter(BarResident::getActive)
.map(BarResident::getBar)
.map(BarEntity::getStops)
.flatMap(List::stream)
.map(StopList::getCocktail)
.map(CocktailEntity::getId)
.toList();
}
private List<Long> getAllowedCocktailIds(Long barId) {
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Long> query = cb.createQuery(Long.class);
Root<ReceiptEntity> receiptRoot = query.from(ReceiptEntity.class);
Join<ReceiptEntity, IngredientEntity> ingredientJoin = receiptRoot.join("ingredient", JoinType.LEFT);
Join<IngredientEntity, BarIngredientStorage> barIngredientStorageJoin = ingredientJoin.join("barIngredients", JoinType.LEFT);
// Внешний подзапрос с NOT EXISTS
Subquery<Long> subquery = query.subquery(Long.class);
Root<ReceiptEntity> receiptSubRoot = subquery.from(ReceiptEntity.class);
Join<ReceiptEntity, IngredientEntity> ingredientSubJoin = receiptSubRoot.join("ingredient", JoinType.LEFT);
// Внутренний подзапрос с NOT EXISTS
Subquery<Long> innerSubquery = subquery.subquery(Long.class);
Root<BarIngredientStorage> barIngredientStorageInnerRoot = innerSubquery.from(BarIngredientStorage.class);
// Условия внутреннего подзапроса
innerSubquery.select(barIngredientStorageInnerRoot.get("id"))
.where(
cb.equal(barIngredientStorageInnerRoot.get("ingredient"), ingredientSubJoin.get("id")),
cb.equal(barIngredientStorageInnerRoot.get("bar").get("id"), barId)
);
// Условия внешнего подзапроса
subquery.select(receiptSubRoot.get("id"))
.where(
cb.equal(receiptSubRoot.get("cocktail").get("id"), receiptRoot.get("cocktail").get("id")),
cb.not(cb.exists(innerSubquery))
);
// Основной запрос
query.select(receiptRoot.get("cocktail").get("id"))
.distinct(true)
.where(
cb.equal(barIngredientStorageJoin.get("bar").get("id"), barId),
cb.not(cb.exists(subquery))
);
return entityManager.createQuery(query).getResultList();
}
public CocktailForListResponseDto findById(Long id) {
CocktailEntity cocktail = repository.findById(id).orElseThrow();
return mapper.cocktailToFullDto(cocktail);
}
@Transactional
public void edit(CocktailForListResponseDto dto) {
CocktailEntity cocktail;
if (dto.getId() == null) {
if (dto.getName() == null) {
throw new RuntimeException("Коктейль не может быть без названия");
}
cocktail = new CocktailEntity();
cocktail.setReceipt(new ArrayList<>());
} else {
cocktail = repository.findById(dto.getId())
.orElseThrow(() -> new RuntimeException("Не удалось найти коктейль с id " + dto.getId()));
}
CategoryEntity category = categoryRepository.findByNameIgnoreCase(dto.getCategory())
.orElseThrow(() -> new RuntimeException("Не удалось найти категорию " + dto.getCategory()));
GlassEntity glassEntity = glassRepository.findByNameIgnoreCase(dto.getGlass())
.orElseThrow(() -> new RuntimeException("Не удалось найти посуду" + dto.getGlass()));
AlcoholicEntity alcoholicEntity = alcoholicRepository.findByName(dto.getAlcoholic())
.orElseThrow(() -> new RuntimeException("Не удалось найти алкогольность" + dto.getAlcoholic()));
cocktail.setName(dto.getName());
cocktail.setInstructions(dto.getInstructions());
cocktail.setImage(dto.getImage());
cocktail.setVideo(cocktail.getVideo());
cocktail.setCategoryEntity(category);
cocktail.setGlassEntity(glassEntity);
cocktail.setAlcoholicEntity(alcoholicEntity);
cocktail.setTags(findTags(dto.getTags()));
cocktail.setRating(cocktail.getRating());
repository.save(cocktail);
editCocktailReceipts(cocktail.getReceipt(), dto.getReceipt(), cocktail);
}
public void editFavourite(Long cocktailId, Long visitorId, boolean put) {
Visitor visitor = visitorsRepository.findById(visitorId).orElseThrow();
Optional<Rating> ratingOpt = ratingRepository.findRatingByCocktailIdAndVisitorId(cocktailId, visitorId);
Rating rating;
if (put) {
CocktailEntity cocktail = repository.findById(cocktailId)
.orElseThrow();
if (ratingOpt.isEmpty()) {
rating = new Rating();
rating.setCocktail(cocktail);
rating.setVisitor(visitor);
} else {
rating = ratingOpt.get();
}
rating.setFavorite(true);
ratingRepository.save(rating);
} else {
if (ratingOpt.isPresent()) {
rating = ratingOpt.get();
rating.setFavorite(false);
ratingRepository.save(rating);
}
}
}
public void setRating(Long cocktailId, Integer rating) {
Long id = ((Visitor) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getId();
Visitor visitor = visitorsRepository.findById(id)
.orElseThrow();
Rating rate;
Optional<Rating> rateOpt = ratingRepository.findRatingByCocktailIdAndVisitorId(cocktailId, id);
if (rateOpt.isEmpty()) {
rate = new Rating();
rate.setVisitor(visitor);
rate.setCocktail(repository.findById(cocktailId).orElseThrow());
rate.setFavorite(false);
} else {
rate = rateOpt.get();
}
rate.setRating(rating);
ratingRepository.save(rate);
}
private void editCocktailReceipts(List<ReceiptEntity> old, List<ReceiptResponseDto> actual, CocktailEntity cocktail) {
for (ReceiptResponseDto receipt : actual) {
if (receipt.getId() == null) {
createNewReceipt(receipt, cocktail);
continue;
}
old.stream().filter(r -> receipt.getId().equals(r.getId()))
.findFirst()
.ifPresent(r -> equalReceipt(r, receipt));
old.removeIf(r -> r.getId().equals(receipt.getId()));
}
old.forEach(r -> receiptRepository.deleteById(r.getId()));
}
private void equalReceipt(ReceiptEntity old, ReceiptResponseDto actual) {
boolean needSave = false;
if (!actual.getIngredient().getId().equals(old.getIngredient().getId())) {
IngredientEntity ingredient = ingredientRepository.findById(actual.getIngredient().getId()).orElseThrow();
old.setIngredient(ingredient);
needSave = true;
}
if (old.getUnit() == null || actual.getUnit() == null ||
!Objects.equals(old.getUnit().getId(), actual.getUnit().getId())) {
old.setUnit(actual.getUnit());
needSave = true;
}
if (!Objects.equals(old.getCount(), actual.getCount())) {
old.setCount(actual.getCount());
needSave = true;
}
if (needSave) {
receiptRepository.save(old);
}
}
private void createNewReceipt(ReceiptResponseDto receipt, CocktailEntity cocktail) {
ReceiptEntity receiptEntity = new ReceiptEntity();
IngredientEntity ingredient = ingredientRepository.findById(receipt.getIngredient().getId()).orElseThrow();
receiptEntity.setIngredient(ingredient);
receiptEntity.setCount(receipt.getCount());
receiptEntity.setUnit(receipt.getUnit());
// receiptEntity.setMeasure(receipt.getMeasure());
receiptEntity.setCocktail(cocktail);
receiptRepository.save(receiptEntity);
}
private List<TagEntity> findTags(String tagString) {
if (tagString == null || tagString.isEmpty()) {
return new ArrayList<>();
}
List<TagEntity> tags = new ArrayList<>();
for (String name : tagString.split(",")) {
if (name.isEmpty()) {
continue;
}
TagEntity tagEntity = tagRepository.findByName(name)
.orElseThrow(() -> new RuntimeException("Не удалось найти тег " + name));
tags.add(tagEntity);
}
return tags;
}
public void inMenuEdit(Long id, Boolean value) {
Visitor visitor = visitorService.getCurrentVisitor();
CocktailEntity entity = repository.findById(id)
.orElseThrow(() -> new RuntimeException("Не удалось найти коктейль с id " + id));
BarEntity bar = visitor.getResidents().stream()
.filter(BarResident::getActive)
.map(BarResident::getBar)
.toList()
.get(0);
Optional<StopList> stop = bar.getStops().stream()
.filter(s -> Objects.equals(s.getCocktail().getId(), id))
.findFirst();
if (value && stop.isPresent()) {
stopListRepository.deleteById(stop.get().getId());
return;
}
if (!value && stop.isEmpty()) {
StopList stopList = new StopList();
stopList.setCocktail(entity);
stopList.setBar(bar);
stopListRepository.save(stopList);
}
}
public CocktailModalDto getForModal(Long id) {
CocktailEntity cocktail = repository.findById(id).orElseThrow(RuntimeException::new);
return mapper.cocktailToModalDto(cocktail);
}
public List<ReceiptResponseDto> getReceipts(Long id) {
return null;
}
public List<CocktailSimpleResponseDto> getSimple() {
return repository.findAll().stream()
.map(CocktailSimpleResponseDto::mapToDto)
.toList();
}
public String savePhoto(MultipartFile file) throws IOException {
File folder = new File(photoFolder);
List<File> files = Arrays.asList(Objects.requireNonNull(folder.listFiles()));
String fileName = getPhotoPath(files, file.getOriginalFilename());
String fullName = photoFolder + "/" + fileName;
file.transferTo(new File(fullName));
log.info("сохранено фото {}", fileName);
return "/assets/cocktails/" + fileName;
}
private String getPhotoPath(List<File> files, String originalName) {
if (files.stream().map(File::getName).anyMatch(name -> name.equals(originalName))) {
String[] split = originalName.split("\\.");
String name = concatName(split) + "_c." + split[split.length - 1];
return getPhotoPath(files, name);
}
return originalName;
}
private String concatName(String[] name) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < name.length - 1; i++) {
sb.append(name[i]);
}
return sb.toString();
}
public void delete(Long id) {
CocktailEntity cocktail = repository.findById(id).orElseThrow(RuntimeException::new);
log.info("Удален коктейль {}", cocktail);
repository.delete(cocktail);
}
}

View File

@@ -0,0 +1,109 @@
package ru.kayashov.bar.service;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import ru.kayashov.bar.controller.dto.ingredient.IngredientResponseDto;
import ru.kayashov.bar.controller.dto.ingredient.IngredientSimpleResponseDto;
import ru.kayashov.bar.mapper.IngredientMapper;
import ru.kayashov.bar.model.entity.BarEntity;
import ru.kayashov.bar.model.entity.BarIngredientStorage;
import ru.kayashov.bar.repository.BarIngredientStorageRepository;
import ru.kayashov.bar.model.entity.BarResident;
import ru.kayashov.bar.model.entity.IngredientEntity;
import ru.kayashov.bar.model.entity.TypeEntity;
import ru.kayashov.bar.model.entity.Visitor;
import ru.kayashov.bar.repository.IngredientRepository;
import ru.kayashov.bar.repository.TypeRepository;
import java.util.List;
import java.util.Objects;
@Slf4j
@Service
@RequiredArgsConstructor
public class IngredientService {
private final VisitorService visitorService;
private final TypeRepository typeRepository;
private final IngredientRepository repository;
private final IngredientMapper mapper;
private final BarIngredientStorageRepository barIngredientStorageRepository;
public IngredientEntity findIngredientByName(String name) {
return repository.findByEnNameIgnoreCase(name)
.orElseThrow(() -> new RuntimeException("Не удалось найти ингредиент с названием " + name));
}
private TypeEntity findTypeByName(String name) {
return typeRepository.findByName(name)
.orElse(null);
}
/**
* Запрос ингредиентов бара
*/
public List<IngredientResponseDto> getAll() {
List<IngredientEntity> ingredients = repository.findAll();
return mapper.mapIngredientsToDtoList(ingredients);
}
public List<IngredientSimpleResponseDto> getAllSimple() {
List<IngredientEntity> ingredients = repository.findAll();
return mapper.mapIngredientsToSimpleDtoList(ingredients);
}
public IngredientEntity getIngredientById(Long id) {
return repository.findById(id).orElseThrow();
}
public void changeBarIngredient(Long id, boolean isHave) {
Visitor visitor = visitorService.getCurrentVisitor();
BarEntity bar = visitor.getResidents()
.stream()
.filter(BarResident::getActive)
.map(BarResident::getBar)
.toList()
.get(0);
List<BarIngredientStorage> storage = bar.getIngredients();
IngredientEntity ingredientEntity = getIngredientById(id);
if (isHave) {
BarIngredientStorage entity = new BarIngredientStorage();
entity.setBar(bar);
entity.setIngredient(ingredientEntity);
//todo: прикрутить позже entity.setMeasure();
entity = barIngredientStorageRepository.save(entity);
storage.add(entity);
} else {
storage.stream()
.filter(s -> Objects.equals(s.getIngredient().getId(), ingredientEntity.getId()))
.forEach(s -> barIngredientStorageRepository.deleteById(s.getId()));
}
}
public boolean saveChange(IngredientResponseDto dto) {
if (dto.getId() == null) {
return false;
}
IngredientEntity entity = repository.findById(dto.getId())
.orElse(null);
if (entity == null) {
return false;
}
entity.setName(dto.getName());
entity.setDescription(dto.getDescription());
// entity.setEnName(dto.getEnName());
// entity.setIsHave(dto.isHave());
entity.setAbv(dto.getAbv());
entity.setAlcohol(dto.getAlcohol());
TypeEntity type = findTypeByName(dto.getType());
if (type == null) {
return false;
}
entity.setType(type);
repository.save(entity);
return true;
}
}

View File

@@ -0,0 +1,104 @@
package ru.kayashov.bar.service;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import ru.kayashov.bar.bot.domain.methods.AbstractSendMessage;
import ru.kayashov.bar.model.entity.BarEntity;
import ru.kayashov.bar.model.entity.BarResident;
import ru.kayashov.bar.model.entity.CocktailEntity;
import ru.kayashov.bar.model.entity.Pay;
import ru.kayashov.bar.model.entity.SessionEntity;
import ru.kayashov.bar.model.entity.Visitor;
import ru.kayashov.bar.repository.CocktailRepository;
import ru.kayashov.bar.repository.OrdersRepository;
import ru.kayashov.bar.repository.VisitorsRepository;
import java.time.LocalDateTime;
import java.util.List;
import static ru.kayashov.bar.model.entity.OrderStatus.CANCEL;
import static ru.kayashov.bar.model.entity.OrderStatus.DONE;
import static ru.kayashov.bar.model.entity.OrderStatus.NEW;
import static ru.kayashov.bar.model.entity.UserRole.ADMIN;
import static ru.kayashov.bar.model.entity.UserRole.BARMEN;
@Service
@RequiredArgsConstructor
public class OrderService {
private final VisitorService visitorService;
private final CocktailRepository cocktailRepository;
private final OrdersRepository ordersRepository;
/**
* Новый заказ
*/
public List<AbstractSendMessage> createOrder(Long visitorId, Long cocktailId) {
Visitor visitor = visitorService.findById(visitorId);
BarEntity bar = visitor.getResidents().stream()
.filter(BarResident::getActive)
.map(BarResident::getBar)
.toList()
.get(0);
SessionEntity session = bar.getSessions().stream()
.filter(SessionEntity::getIsActive)
.toList()
.get(0);
CocktailEntity cocktail = cocktailRepository.findById(cocktailId).orElseThrow();
Pay pay = new Pay();
pay.setStatus(NEW);
pay.setVisitor(visitor);
pay.setCocktail(cocktail);
pay.setSession(session);
pay.setCreatedAt(LocalDateTime.now());
ordersRepository.save(pay);
return bar.getVisitors().stream()
.filter(BarResident::getActive)
.filter(BarResident::getInvited)
.filter(b -> b.getRole() == ADMIN || b.getRole() == BARMEN)
.map(BarResident::getVisitor)
.map(admin -> createOrderMessage(admin, visitor, cocktail))
.toList();
}
private AbstractSendMessage createOrderMessage(Visitor admin, Visitor client, CocktailEntity cocktail) {
return AbstractSendMessage.builder()
.chatId(admin.getId())
.message(client.getName() + " " + client.getLastName() + " заказал(а) коктейль " + cocktail.getName())
.build();
}
/**
* Обновить статус заказа
*/
public AbstractSendMessage updateOrder(boolean check, long l) {
Pay pay = ordersRepository.findById(l).orElseThrow();
pay.setStatus(check ? DONE : CANCEL);
pay.setClosedAt(LocalDateTime.now());
ordersRepository.save(pay);
return AbstractSendMessage.builder()
.chatId(pay.getVisitor().getId())
.message("Коктейль " + pay.getCocktail().getName() + (check ? " готов" : " отменен"))
.build();
}
/**
* Получить заказ из очереди
*/
public List<Pay> getOrders() {
Visitor visitor = visitorService.getCurrentVisitor();
return visitor.getResidents().stream()
.filter(BarResident::getActive)
.map(BarResident::getBar)
.map(BarEntity::getSessions)
.flatMap(List::stream)
.filter(SessionEntity::getIsActive)
.map(SessionEntity::getOrders)
.flatMap(List::stream)
.toList();
}
}

View File

@@ -0,0 +1,55 @@
package ru.kayashov.bar.service;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import ru.kayashov.bar.model.entity.ParserEntity;
import ru.kayashov.bar.repository.ParserEntityRepository;
import java.util.List;
@Service
@RequiredArgsConstructor
public class ParserQueueService {
private final ParserEntityRepository repository;
public Long getIngredientOffset() {
return getEntity().getIngredientId();
}
public Long getCocktailOffset() {
return getEntity().getCocktailId();
}
public void setStepIngredients(long id, int step) {
ParserEntity entity = getEntity();
entity.setIngredientId(id);
entity.setIngredientError(entity.getIngredientError() + step);
repository.save(entity);
}
public void setStepCocktails(long id, int step) {
ParserEntity entity = getEntity();
entity.setCocktailId(id);
entity.setCocktailError(entity.getCocktailError() + step);
repository.save(entity);
}
private ParserEntity getEntity() {
List<ParserEntity> entities = repository.findAll();
if(entities.isEmpty()) {
ParserEntity entity = getNewEntity();
return repository.save(entity);
}
return entities.get(0);
}
private ParserEntity getNewEntity() {
ParserEntity entity = new ParserEntity();
entity.setIngredientId(1L);
entity.setCocktailId(1L);
entity.setCocktailError(0L);
entity.setCocktailError(0L);
return entity;
}
}

View File

@@ -0,0 +1,22 @@
package ru.kayashov.bar.service;
import lombok.experimental.UtilityClass;
import org.springframework.http.RequestEntity;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.RestTemplate;
import java.util.Optional;
@UtilityClass
public class RestUtil {
public static <T> Optional<ResponseEntity<T>> sendRequest(Class<T> responseType, RequestEntity<?> request) {
try {
RestTemplate restTemplate = new RestTemplate();
return Optional.of(restTemplate.exchange(request, responseType));
} catch (HttpClientErrorException e) {
return Optional.empty();
}
}
}

View File

@@ -0,0 +1,190 @@
package ru.kayashov.bar.service;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import ru.kayashov.bar.controller.dto.bar.BarResponseDto;
import ru.kayashov.bar.controller.dto.ingredient.IngredientSimpleResponseDto;
import ru.kayashov.bar.controller.dto.cocktail.ReceiptResponseDto;
import ru.kayashov.bar.model.entity.BarEntity;
import ru.kayashov.bar.model.entity.BarResident;
import ru.kayashov.bar.repository.BarResidentRepository;
import ru.kayashov.bar.model.entity.CategoryEntity;
import ru.kayashov.bar.model.entity.CocktailEntity;
import ru.kayashov.bar.model.entity.GlassEntity;
import ru.kayashov.bar.model.entity.SessionEntity;
import ru.kayashov.bar.model.entity.UserRole;
import ru.kayashov.bar.model.entity.Visitor;
import ru.kayashov.bar.repository.BarEntityRepository;
import ru.kayashov.bar.repository.CategoryRepository;
import ru.kayashov.bar.repository.CocktailRepository;
import ru.kayashov.bar.repository.GlassRepository;
import ru.kayashov.bar.repository.RatingRepository;
import ru.kayashov.bar.repository.SessionRepository;
import ru.kayashov.bar.repository.VisitorsRepository;
import java.util.Comparator;
import java.util.List;
@Slf4j
@Service
@RequiredArgsConstructor
public class SessionService {
private final SessionRepository sessionRepository;
private final VisitorsRepository visitorsRepository;
private final GlassRepository glassRepository;
private final CategoryRepository categoryRepository;
private final CocktailRepository cocktailRepository;
private final RatingRepository ratingRepository;
private final VisitorService visitorService;
private final BarEntityRepository barEntityRepository;
private final BarResidentRepository barResidentRepository;
/**
* Поиск матрицы коктейлей
* Справочник состоит из количества недостающих компонентов и списка коктейлей
*/
// public Map<Long, List<CocktailEntity>> getCocktailMatrix() {
// return cocktailRepository.findAll().stream()
// .collect(Collectors.groupingBy(this::getRemainingIngredient));
// }
/**
* Поиск активной сессии
*/
public SessionEntity findActiveSession() {
List<SessionEntity> sessions = sessionRepository.findAll()
.stream()
.sorted(Comparator.comparingLong(SessionEntity::getId).reversed())
.limit(1)
.toList();
if (!sessions.isEmpty()) {
return sessions.get(0);
}
return createEmptySession();
}
public Visitor getVisitor() {
Long id = ((Visitor) SecurityContextHolder.getContext()
.getAuthentication()
.getPrincipal())
.getId();
return visitorsRepository.findById(id)
.orElseThrow();
}
public SessionEntity createEmptySession() {
BarEntity bar = visitorService.getCurrentVisitor().getResidents()
.stream()
.filter(BarResident::getActive)
.map(BarResident::getBar)
.toList()
.get(0);
SessionEntity session = new SessionEntity();
session.setBar(bar);
session.setIsActive(true);
return sessionRepository.save(session);
}
// private long getRemainingIngredient(CocktailEntity cocktail) {
// return cocktail.getReceipt()
// .stream()
// .map(ReceiptEntity::getIngredient)
//// .map(IngredientEntity::getIsHave)
// .filter(b -> !b).count();
// }
public List<GlassEntity> getGlassList() {
return glassRepository.findAll();
}
public List<CategoryEntity> getCategoryList() {
return categoryRepository.findAll();
}
public List<ReceiptResponseDto> getReceiptList(Long cocktailId) {
CocktailEntity cocktail = cocktailRepository.findById(cocktailId).orElseThrow();
return cocktail.getReceipt().stream()
.map(e -> ReceiptResponseDto.builder()
.id(e.getId())
.ingredient(IngredientSimpleResponseDto.mapToDto(e.getIngredient()))
.measure(e.getMeasure())
.build())
.toList();
}
public List<BarResponseDto> getBarList(Boolean my) {
List<BarResident> residents = visitorService.getCurrentVisitor().getResidents();
if (my) {
return residents.stream()
.map(r -> mapBarToDto(r.getBar(), r, true))
.toList();
}
List<Long> myBar = residents.stream()
.map(BarResident::getBar)
.map(BarEntity::getId)
.toList();
return barEntityRepository.findAll().stream()
.filter(b -> !myBar.contains(b.getId()))
.map(b -> mapBarToDto(b, null, false))
.toList();
}
public void addToMyList(BarResponseDto dto) {
Visitor visitor = visitorService.getCurrentVisitor();
BarEntity bar = barEntityRepository.findById(dto.getId()).orElseThrow();
boolean noEnter = visitor.getResidents().stream().filter(BarResident::getActive).toList().isEmpty();
BarResident resident = new BarResident();
resident.setBar(bar);
resident.setInvited(true);
resident.setRole(UserRole.USER);
resident.setVisitor(visitor);
resident.setActive(noEnter);
barResidentRepository.save(resident);
}
public void enterChange(Long id, Boolean value) {
Visitor visitor = visitorService.getCurrentVisitor();
List<BarResident> residents = visitor.getResidents()
.stream()
.filter(r -> r.getBar().getId().equals(id))
.toList();
if(residents.isEmpty()) {
throw new RuntimeException("Бар с id " + id + " отсутствует в списке баров пользователя с id " + visitor.getId());
}
residents.stream()
.peek(r -> r.setActive(value))
.forEach(barResidentRepository::save);
log.info("Пользователь {}-{} {} {} c id {}",
visitor.getId(),
visitor.getName().strip(),
visitor.getLastName().strip(),
value ? "вошел в бар" : "вышел из бара",
id);
}
private BarResponseDto mapBarToDto(BarEntity bar, BarResident resident, Boolean my) {
BarResponseDto dto = new BarResponseDto();
dto.setId(bar.getId());
dto.setName(bar.getName());
boolean barOpen = !bar.getSessions().stream().filter(SessionEntity::getIsActive).toList().isEmpty();
if (my) {
boolean invited = resident.getInvited();
dto.setOpen(barOpen && invited);
dto.setEnter(resident.getActive());
dto.setMyRole(resident.getRole().toString());
} else {
dto.setOpen(barOpen);
dto.setEnter(false);
dto.setMyRole(UserRole.USER.toString());
}
return dto;
}
}

View File

@@ -0,0 +1,78 @@
package ru.kayashov.bar.service;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import ru.kayashov.bar.controller.dto.VisitorResponseDto;
import ru.kayashov.bar.model.entity.BarEntity;
import ru.kayashov.bar.model.entity.BarIngredientStorage;
import ru.kayashov.bar.model.entity.BarResident;
import ru.kayashov.bar.repository.BarResidentRepository;
import ru.kayashov.bar.model.entity.IngredientEntity;
import ru.kayashov.bar.model.entity.Visitor;
import ru.kayashov.bar.repository.VisitorsRepository;
import java.util.List;
import java.util.Objects;
@Service
@RequiredArgsConstructor
public class VisitorService {
private final VisitorsRepository visitorsRepository;
private final BarResidentRepository barResidentRepository;
public Visitor getCurrentVisitor() {
Long id = ((Visitor) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getId();
return findById(id);
}
public Visitor findById(Long id) {
return visitorsRepository.findById(id).orElseThrow(() -> new RuntimeException("Visitor not found. id: " + id));
}
public List<Long> getAllowedIngredients() {
return getCurrentVisitor().getResidents()
.stream()
.filter(BarResident::getActive)
.map(BarResident::getBar)
.map(BarEntity::getIngredients)
.flatMap(List::stream)
.map(BarIngredientStorage::getIngredient)
.map(IngredientEntity::getId)
.toList();
}
public List<VisitorResponseDto> findAll() {
return getCurrentVisitor().getResidents().stream()
.filter(BarResident::getActive)
.map(BarResident::getBar)
.map(BarEntity::getVisitors)
.flatMap(List::stream)
.map(this::mapBarResidentToDto)
.toList();
}
private VisitorResponseDto mapBarResidentToDto(BarResident resident) {
VisitorResponseDto dto = new VisitorResponseDto();
dto.setId(resident.getVisitor().getId());
dto.setName(resident.getVisitor().getName());
dto.setLastName(resident.getVisitor().getLastName());
dto.setInvited(resident.getInvited());
dto.setRole(resident.getRole().toString());
dto.setIsActive(resident.getActive());
return dto;
}
public void invited(Boolean value, Long id) {
getCurrentVisitor().getResidents()
.stream()
.filter(BarResident::getActive)
.map(BarResident::getBar)
.map(BarEntity::getVisitors)
.flatMap(List::stream)
.filter(v -> Objects.equals(v.getVisitor().getId(), id))
.peek(v -> v.setInvited(value))
.forEach(barResidentRepository::save);
}
}

View File

@@ -0,0 +1,47 @@
package ru.kayashov.bar.service.integration.cocktail;
import org.springframework.http.HttpEntity;
import org.springframework.http.RequestEntity;
import org.springframework.stereotype.Service;
import ru.kayashov.bar.model.Cocktail;
import ru.kayashov.bar.model.Ingredient;
import ru.kayashov.bar.model.api.cocktail.Cocktails;
import ru.kayashov.bar.model.api.cocktail.Ingredients;
import ru.kayashov.bar.service.RestUtil;
import java.util.Collections;
import java.util.List;
@Service
public class CocktailApiService {
public Ingredient getIngredientById(long id) {
String url = "https://www.thecocktaildb.com/api/json/v1/1/lookup.php?iid=";
return RestUtil.sendRequest(Ingredients.class,
RequestEntity.get(url + id).build())
.map(HttpEntity::getBody)
.map(Ingredients::getIngredients)
.map(i -> i.get(0))
.orElse(null);
}
public Cocktail getCocktailById(long id) {
String url = "https://www.thecocktaildb.com/api/json/v1/1/lookup.php?i=";
return RestUtil.sendRequest(Cocktails.class,
RequestEntity.get(url + id).build())
.map(HttpEntity::getBody)
.map(Cocktails::getDrinks)
.map(i -> i.get(0))
.orElse(null);
}
public List<Cocktail> getCocktailByLiteral(String literal) {
String url = "https://www.thecocktaildb.com/api/json/v1/1/search.php?f=";
return RestUtil.sendRequest(Cocktails.class,
RequestEntity.get(url + literal).build())
.map(HttpEntity::getBody)
.map(Cocktails::getDrinks)
.orElse(Collections.emptyList());
}
}

View File

@@ -0,0 +1,53 @@
package ru.kayashov.bar.service.integration.translate;
import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.RequestEntity;
import org.springframework.http.ResponseEntity;
import ru.kayashov.bar.model.api.translate.Request;
import ru.kayashov.bar.model.api.translate.Response;
import ru.kayashov.bar.model.api.translate.Translate;
import ru.kayashov.bar.service.RestUtil;
import java.util.List;
import java.util.Optional;
@Slf4j
@UtilityClass
public class TranslateService {
private static final String TOKEN = "t1.9euelZrJyoyTmZGQyc2TiZCWlYyLiu3rnpWazsubi8vOzcycms6Znc2dkI7l8_dgXlNC-e9UAyJ4_t3z9yANUUL571QDInj-zef1656Vms2Uio2JmJ6OxpucmoqNjZ6J7_zF656Vms2Uio2JmJ6OxpucmoqNjZ6J.uXSVsrpZcSgQ9qz0-wx6WR79rvq14QCtlC6tnWvah33YRrNqSEBFXBwqMoEq18nG3wHElKE4NsHXK3lxV9SSBQ";
public static String translate(String text) {
return sendTranslate(text)
.map(TranslateService::getTranslateText)
.orElseThrow(RuntimeException::new);
}
public static String softTranslate(String text) {
Optional<ResponseEntity<Response>> opt = sendTranslate(text);
if(opt.isPresent()) {
return TranslateService.getTranslateText(opt.get());
} else {
log.warn("Не удалось перевести текст {}", text);
return text;
}
}
private static Optional<ResponseEntity<Response>> sendTranslate(String text) {
return RestUtil.sendRequest(Response.class,
RequestEntity.post("https://translate.api.cloud.yandex.net/translate/v2/translate")
.header("Authorization", "Bearer " + TOKEN)
.body(new Request(List.of(text))));
}
private static String getTranslateText(ResponseEntity<Response> response) {
Response resp = response.getBody();
StringBuilder sb = new StringBuilder();
List<Translate> translates = resp.getTranslations();
for(Translate translate : translates) {
sb.append(translate.getText());
}
return sb.toString();
}
}