Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[PAYMENT] Implemented beta controller and service, added swagger to the controller #16

Merged
merged 19 commits into from
Oct 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
6c00b43
added base stucture for paymentController, added Payment dtos and sam…
ivan0dyatlyukkk Oct 3, 2023
736530f
Merge branch 'main' into feat-payment
ivan0dyatlyukkk Oct 3, 2023
ab6a03d
Merge branch 'main' into feat-payment
ivan0dyatlyukkk Oct 3, 2023
7578376
added stategy for choosing payment type, created initial structures f…
ivan0dyatlyukkk Oct 3, 2023
04bea7c
testing creating payment session
ivan0dyatlyukkk Oct 3, 2023
93cf475
implemented create payment and create stripe session endpoint, adjust…
ivan0dyatlyukkk Oct 3, 2023
17640a5
improved payment controller, service and repository, adjusted stripe …
ivan0dyatlyukkk Oct 3, 2023
62657c5
added swagger to the payment controller and fixed checkstyle issues
ivan0dyatlyukkk Oct 3, 2023
0b203a5
added an option for easy testing
ivan0dyatlyukkk Oct 3, 2023
855d029
Merge branch 'main' into feat-payment
ivan0dyatlyukkk Oct 3, 2023
0a8b36c
adjusted test properties file
ivan0dyatlyukkk Oct 3, 2023
95b7be5
Merge remote-tracking branch 'origin/feat-payment' into feat-payment
ivan0dyatlyukkk Oct 3, 2023
422d6d0
Update application.properties
ivan0dyatlyukkk Oct 3, 2023
425ad4e
Updated PaymentAmountHandlerStrategy.java
ivan0dyatlyukkk Oct 3, 2023
1506abd
Updated PaymentService.java
ivan0dyatlyukkk Oct 3, 2023
6d1bcba
Merge branch 'main' into feat-payment
ivan0dyatlyukkk Oct 4, 2023
5731675
fixed small mistakes
ivan0dyatlyukkk Oct 4, 2023
81328bc
Merge remote-tracking branch 'origin/feat-payment' into feat-payment
ivan0dyatlyukkk Oct 4, 2023
3aa6990
resolved all of conflicts and updated the branch for implementing pay…
ivan0dyatlyukkk Oct 4, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 7 additions & 8 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
<version>2.1.0</version>
</dependency>
<dependency>
<groupId>org.liquibase</groupId>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-core</artifactId>
<version>${liquibase.version}</version>
</dependency>
Expand All @@ -49,9 +49,9 @@
<version>${liquibase.version}</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>8.1.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
Expand Down Expand Up @@ -79,9 +79,9 @@
<version>${mapstruct.version}</version>
</dependency>
<dependency>
<groupId>jakarta.validation</groupId>
<artifactId>jakarta.validation-api</artifactId>
<version>2.0.2</version>
<groupId>com.stripe</groupId>
<artifactId>stripe-java</artifactId>
<version>23.7.0</version>
</dependency>
<dependency>
<groupId>org.telegram</groupId>
Expand Down Expand Up @@ -164,5 +164,4 @@
</plugin>
</plugins>
</build>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package com.project.carsharingapp.controller;

import com.project.carsharingapp.dto.payment.CreatePaymentSessionRequestDto;
import com.project.carsharingapp.model.Payment;
import com.project.carsharingapp.service.PaymentService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Pageable;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@Tag(name = "Payment management", description = "Endpoint for managing payments")
@RestController
@RequestMapping("/payments")
@RequiredArgsConstructor
public class PaymentController {
private final PaymentService paymentService;

@GetMapping
@Operation(summary = "Get all user's payments")
public List<Payment> getAll(Pageable pageable) {
return paymentService.getAll(pageable);
}

@PostMapping
@Operation(summary = "Create a new payment session")
public Payment create(
@RequestBody @Valid CreatePaymentSessionRequestDto requestDto
) {
return paymentService.create(requestDto);
}

@GetMapping("/success")
@Operation(summary = "Redirect endpoint in case of successful payment")
private String redirectToSuccessPage(@RequestParam String sessionId) {
paymentService.updateStatus(sessionId);
return "success";
}

@GetMapping("/cancel")
@Operation(summary = "Redirect endpoint in case of paused payment")
private String redirectToFailedPage() {
return "cancel";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import com.project.carsharingapp.dto.rental.CreateRentalRequestDto;
import com.project.carsharingapp.dto.rental.RentalDto;
import com.project.carsharingapp.dto.rental.SetActualReturnDateRequestDto;
import com.project.carsharingapp.service.rental.RentalService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
Expand Down Expand Up @@ -57,7 +56,7 @@ public RentalDto getById(@PathVariable Long id) {
@ResponseStatus(HttpStatus.OK)
@Operation(summary = "Set actual return date",
description = "Set actual return date and increase car inventory by 1")
public RentalDto setActualReturnDay(Long id) { // Authnetication
public RentalDto setActualReturnDay(Long id) {
return rentalService.setActualReturnDay(id);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.project.carsharingapp.dto.payment;

import jakarta.validation.constraints.NotNull;
import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class CreatePaymentSessionRequestDto {
@NotNull
private Long rentalId;
@NotNull
private String type;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package com.project.carsharingapp.dto.payment;

public class PaymentResponseDto {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the purpose of using empty class?

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.project.carsharingapp.dto.rental;

public record RentalSearchParametersDto(String[] userId,
String[] isActive) {
}
public record RentalSearchParametersDto(
String[] userId,
String[] isActive
) {
}
2 changes: 1 addition & 1 deletion src/main/java/com/project/carsharingapp/model/Payment.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public class Payment {
private Type type;
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "rental_id", nullable = false)
private Rental rentalId;
private Rental rental;
@Column(name = "session_url", nullable = false)
private String sessionUrl;
@Column(name = "session_id", nullable = false)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
package com.project.carsharingapp.repository;

import com.project.carsharingapp.model.Payment;
import java.util.Optional;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;

public interface PaymentRepository extends JpaRepository<Payment, Long> {
Optional<Payment> findBySessionId(String sessionId);

Page<Payment> findAll(Pageable pageable);
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,10 @@

@Repository
public interface RentalRepository extends JpaRepository<Rental, Long> {
@Query("FROM Rental r LEFT JOIN FETCH r.car "
+ "LEFT JOIN FETCH r.user WHERE r.id = :id")
Optional<Rental> findById(Long id);

@Query("FROM Rental r WHERE r.user.id = :userId AND r.isActive = :isActive")
List<Rental> findRentalsByUserIdAndActiveStatus(Long userId, boolean isActive);

// @Query("FROM Rental r WHERE r.user.id = :userId AND r.isActive = :isActive")
// Optional<Rental>findRentalByUserIdAndActiveStatus(Long userId, boolean isActive);


}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.project.carsharingapp.repository.rentals.spec;


import static com.project.carsharingapp.repository.rentals.RentalSpecificationBuilder.USER_ID_KEY;

import com.project.carsharingapp.model.Rental;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.project.carsharingapp.service;

import com.project.carsharingapp.model.Payment;
import java.math.BigDecimal;

public interface PaymentAmountHandler {
Long getPaymentAmount(BigDecimal dailyFee, int numberOfDays);

boolean isApplicable(Payment.Type type);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.project.carsharingapp.service;

import com.project.carsharingapp.dto.payment.CreatePaymentSessionRequestDto;
import com.project.carsharingapp.model.Payment;
import java.util.List;
import org.springframework.data.domain.Pageable;

public interface PaymentService {
Payment create(CreatePaymentSessionRequestDto requestDto);

Payment updateStatus(String sessionId);

List<Payment> getAll(Pageable pageable);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.project.carsharingapp.service.impl;

import com.project.carsharingapp.model.Payment;
import com.project.carsharingapp.service.PaymentAmountHandler;
import java.math.BigDecimal;
import org.springframework.stereotype.Component;

@Component
public class FineAmountHandler implements PaymentAmountHandler {
private static final BigDecimal FINE_MULTIPLIER = BigDecimal.valueOf(1.25);

@Override
public Long getPaymentAmount(BigDecimal dailyFee, int numberOfDays) {
return dailyFee.multiply(FINE_MULTIPLIER).longValue() * numberOfDays;
}

@Override
public boolean isApplicable(Payment.Type type) {
return type.equals(Payment.Type.FINE);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.project.carsharingapp.service.impl;

import com.project.carsharingapp.model.Payment;
import com.project.carsharingapp.service.PaymentAmountHandler;
import java.util.List;
import java.util.NoSuchElementException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class PaymentAmountHandlerStrategy {
@Autowired
private List<PaymentAmountHandler> paymentAmountHandlers;

public PaymentAmountHandler getHandler(Payment.Type type) {
return paymentAmountHandlers.stream()
.filter(paymentAmountHandler -> paymentAmountHandler.isApplicable(type))
.findAny()
.orElseThrow(() ->
new NoSuchElementException("Can't find a PaymentAmountHandler "
+ "for such type as: " + type)
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package com.project.carsharingapp.service.impl;

import com.project.carsharingapp.dto.payment.CreatePaymentSessionRequestDto;
import com.project.carsharingapp.exception.EntityNotFoundException;
import com.project.carsharingapp.model.Payment;
import com.project.carsharingapp.model.Rental;
import com.project.carsharingapp.repository.PaymentRepository;
import com.project.carsharingapp.repository.rentals.RentalRepository;
import com.project.carsharingapp.service.PaymentService;
import com.stripe.exception.StripeException;
import com.stripe.model.checkout.Session;
import java.math.BigDecimal;
import java.util.List;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

@Service
@RequiredArgsConstructor
public class PaymentServiceImpl implements PaymentService {
private final RentalRepository rentalRepository;
private final PaymentRepository paymentRepository;
private final StripeService stripeService;

@Override
public Payment create(CreatePaymentSessionRequestDto requestDto) {
Rental rental = rentalRepository.findById(requestDto.getRentalId()).orElseThrow(
() -> new EntityNotFoundException("Can't find a Rental by id: "
+ requestDto.getRentalId())
);
Payment.Type type = Payment.Type.valueOf(requestDto.getType());
try {
Session session = stripeService.createSession(rental, type);
Payment payment = generatePayment(session, rental, type);
return paymentRepository.save(payment);
} catch (StripeException e) {
throw new RuntimeException("Can't create a stripe checkout session!");
}
}

@Override
public Payment updateStatus(String sessionId) {
Payment payment = paymentRepository.findBySessionId(sessionId).orElseThrow(
() -> new EntityNotFoundException("Can't find a Payment by the session")
);
payment.setStatus(Payment.Status.PAID);
return paymentRepository.save(payment);
}

@Override
public List<Payment> getAll(Pageable pageable) {
return paymentRepository.findAll(pageable).stream().collect(Collectors.toList());
}

private Payment generatePayment(Session session, Rental rental, Payment.Type type) {
Payment payment = new Payment();
payment.setStatus(Payment.Status.PENDING);
payment.setType(type);
payment.setRental(rental);
payment.setSessionUrl(session.getUrl());
payment.setSessionId(session.getId());
payment.setAmount(BigDecimal.valueOf(session.getAmountTotal()));
return payment;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.project.carsharingapp.service.impl;

import com.project.carsharingapp.model.Payment;
import com.project.carsharingapp.service.PaymentAmountHandler;
import java.math.BigDecimal;
import org.springframework.stereotype.Component;

@Component
public class RegularPaymentAmountHandler implements PaymentAmountHandler {
@Override
public Long getPaymentAmount(BigDecimal dailyFee, int numberOfDays) {
return dailyFee.longValue() * numberOfDays;
}

@Override
public boolean isApplicable(Payment.Type type) {
return type.equals(Payment.Type.PAYMENT);
}
}
Loading
Loading