package de.rwth.idsg.bikeman.app.service;
import de.rwth.idsg.bikeman.app.dto.ChangeAddressDTO;
import de.rwth.idsg.bikeman.app.dto.ChangePasswordDTO;
import de.rwth.idsg.bikeman.app.dto.ChangePinDTO;
import de.rwth.idsg.bikeman.app.dto.ChangeTariffDTO;
import de.rwth.idsg.bikeman.app.dto.ViewBookedTariffDTO;
import de.rwth.idsg.bikeman.app.dto.ViewCustomerDTO;
import de.rwth.idsg.bikeman.app.dto.ViewTransactionDTO;
import de.rwth.idsg.bikeman.app.exception.AppErrorCode;
import de.rwth.idsg.bikeman.app.exception.AppException;
import de.rwth.idsg.bikeman.app.repository.AppCustomerRepository;
import de.rwth.idsg.bikeman.app.repository.AppTransactionRepository;
import de.rwth.idsg.bikeman.domain.Address;
import de.rwth.idsg.bikeman.domain.BookedTariff;
import de.rwth.idsg.bikeman.domain.CardAccount;
import de.rwth.idsg.bikeman.domain.Customer;
import de.rwth.idsg.bikeman.domain.TariffCategory;
import de.rwth.idsg.bikeman.domain.User;
import de.rwth.idsg.bikeman.repository.CardAccountRepository;
import de.rwth.idsg.bikeman.repository.TariffRepository;
import de.rwth.idsg.bikeman.repository.UserRepository;
import de.rwth.idsg.bikeman.service.UserService;
import de.rwth.idsg.bikeman.web.rest.exception.DatabaseException;
import lombok.extern.slf4j.Slf4j;
import org.joda.time.LocalDateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.Optional;
@Service
@Slf4j
public class AppCurrentCustomerService {
@Autowired
private AppCustomerRepository appCustomerRepository;
@Autowired
private UserRepository userRepository;
@Autowired
private UserService userService;
@Autowired
private CardAccountRepository cardAccountRepository;
@Autowired
private TariffRepository tariffRepository;
@Autowired
private AppTransactionRepository appTransactionRepository;
@Autowired
private PasswordEncoder passwordEncoder;
public ViewCustomerDTO get() throws DatabaseException {
return appCustomerRepository.findOne(
userService.getUserWithAuthorities().getUserId());
}
@Transactional
public Boolean changePin(ChangePinDTO dto) {
Customer customer = this.getCurrentCustomer();
CardAccount cardAccount = customer.getCardAccount();
if (!passwordEncoder.matches(dto.getPassword(), customer.getPassword())) {
return false;
}
cardAccount.setCardPin(dto.getCardPin());
cardAccountRepository.save(cardAccount);
return true;
}
@Transactional
public Boolean changePassword(ChangePasswordDTO dto) {
Customer customer = this.getCurrentCustomer();
if (!passwordEncoder.matches(dto.getOldPassword(), customer.getPassword())) {
return false;
}
if (!dto.getPassword().equals(dto.getPasswordConfirm())) {
throw new AppException("Password and confirmation do not match", AppErrorCode.VALIDATION_FAILED);
}
userService.changePassword(dto.getPassword());
return true;
}
@Transactional
public Boolean changeAddress(ChangeAddressDTO dto) {
Customer customer = this.getCurrentCustomer();
// TODO: do not replace old address in the database but mark it as old and create a new object
Address address = customer.getAddress();
address.setStreetAndHousenumber(dto.getStreetAndHousenumber());
address.setZip(dto.getZip());
address.setCity(dto.getCity());
address.setCountry(dto.getCountry());
userRepository.save(customer);
return true;
}
@Transactional(readOnly = true)
public List<ViewTransactionDTO> getClosedTransactions(Integer page) throws DatabaseException {
return appTransactionRepository.findByCustomerPaginated(this.getCurrentCustomer(), page);
}
@Transactional(readOnly = true)
public Optional<ViewTransactionDTO> getOpenTransaction() throws DatabaseException {
List<ViewTransactionDTO> transactions = appTransactionRepository.findOpenByCustomer(this.getCurrentCustomer());
if (transactions.isEmpty()) {
return Optional.empty();
}
// currently only the oldest open transaction is being returned
return Optional.of(transactions.get(0));
}
public ViewBookedTariffDTO getTariff() {
Customer customer = this.getCurrentCustomer();
BookedTariff currentTariff = customer.getCardAccount().getCurrentTariff();
ViewBookedTariffDTO dto = ViewBookedTariffDTO.builder()
.tariffId(currentTariff.getTariff().getTariffId())
.name(currentTariff.getName())
.automaticRenewal(customer.getCardAccount().getAutoRenewTariff())
.expiryDateTime(currentTariff.getBookedUntil())
.build();
return dto;
}
@Transactional
public ChangeTariffDTO setTariff(ChangeTariffDTO dto) throws AppException {
Customer customer = this.getCurrentCustomer();
BookedTariff currentTariff = customer.getCardAccount().getCurrentTariff();
if (currentTariff.getTariff().getTariffId().equals(dto.getTariffId())) {
throw new AppException("Old and new tariff are equal!", AppErrorCode.CONSTRAINT_FAILED);
}
if ((currentTariff.getBookedUntil() != null)
&& (currentTariff.getBookedUntil().compareTo(LocalDateTime.now()) == 1)) {
throw new AppException("Tariff change not possible due to active subscription!", AppErrorCode.CONSTRAINT_FAILED);
}
BookedTariff updateBookedTariff = new BookedTariff();
updateBookedTariff.setBookedFrom(new LocalDateTime());
if (tariffRepository.findByTariffId(dto.getTariffId()).getTerm() == null) {
updateBookedTariff.setBookedUntil(null);
} else {
updateBookedTariff.setBookedUntil(new LocalDateTime().plusDays(
tariffRepository.findByTariffId(dto.getTariffId()).getTerm()
));
}
updateBookedTariff.setTariff(tariffRepository.findByTariffId(dto.getTariffId()));
customer.getCardAccount().setCurrentTariff(updateBookedTariff);
this.enableAutomaticRenewal();
return dto;
}
@Transactional
public Boolean enableAutomaticRenewal() throws AppException {
this.getCurrentCustomer().getCardAccount().setAutoRenewTariff(true);
return true;
}
@Transactional
public Boolean disableAutomaticRenewal() throws AppException {
CardAccount cardAccount = this.getCurrentCustomer().getCardAccount();
if (cardAccount.getCurrentTariff().getTariff().getCategory().equals(TariffCategory.Default)) {
return false;
}
cardAccount.setAutoRenewTariff(false);
return true;
}
public Customer getCurrentCustomer() {
User user = userService.getUserWithAuthorities();
if (user instanceof Customer) {
return (Customer) user;
} else {
return null;
}
}
}