Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.soupulsar.application.dto.request;

import com.soupulsar.domain.model.enums.PaymentMethod;
import com.soupulsar.domain.model.vo.Money;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;

import java.util.UUID;

public record CreatePaymentRequest(

@NotNull(message = "Session ID cannot be null")
UUID sessionId,
@NotNull(message = "Specialist ID cannot be null")
UUID specialistId,
@NotNull(message = "Client ID cannot be null")
UUID clientId,
@NotNull(message = "Price cannot be null")
Money price,
Money discount,
@NotBlank(message = "Payment method cannot be blank")
PaymentMethod paymentMethod
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package com.soupulsar.application.usecase.payment;

import com.soupulsar.application.dto.request.CreatePaymentRequest;
import com.soupulsar.domain.exceptions.PaymentSplitRuleNotFoundException;
import com.soupulsar.domain.exceptions.UserNotFoundException;
import com.soupulsar.domain.model.payment.Payment;
import com.soupulsar.domain.model.payment.PaymentSplitRule;
import com.soupulsar.domain.model.specialist.SpecialistProfile;
import com.soupulsar.domain.model.vo.Money;
import com.soupulsar.domain.model.vo.PaymentAmounts;
import com.soupulsar.domain.model.vo.PaymentSplit;
import com.soupulsar.domain.repository.PaymentRepository;
import com.soupulsar.domain.repository.PaymentSplitRuleRepository;
import com.soupulsar.domain.repository.SpecialistProfileRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import java.util.Comparator;
import java.util.List;
import java.util.UUID;

@Slf4j
@RequiredArgsConstructor
public class CreatePaymentUseCase {

private final PaymentRepository paymentRepository;
private final PaymentSplitRuleRepository paymentSplitRuleRepository;
private final SpecialistProfileRepository specialistProfileRepository;

public void execute(CreatePaymentRequest request) {

PaymentAmounts amounts = new PaymentAmounts(request.price(), request.discount());
PaymentSplitRule splitRule = getPaymentSplitRule(request.specialistId());
Money platformAmount = splitRule.getPlatformPercentage().applyTo(amounts.getFinalAmount());
Money specialistAmount = amounts.getFinalAmount().subtract(platformAmount);
PaymentSplit split = new PaymentSplit(platformAmount, specialistAmount);

Payment payment = Payment.create(
request.sessionId(),
request.specialistId(),
request.clientId(),
amounts,
split,
request.paymentMethod()
);
paymentRepository.save(payment);

log.info(
"Payment created: paymentId={}, sessionId={}, specialistId={}, clientId={}, finalAmount={}",
payment.getId(),
request.sessionId(),
request.specialistId(),
request.clientId(),
amounts.getFinalAmount()
);
}

private PaymentSplitRule getPaymentSplitRule(UUID specialistId) {

SpecialistProfile profile = specialistProfileRepository.findById(specialistId)
.orElseThrow(() -> new UserNotFoundException(specialistId));

List<PaymentSplitRule> rules = paymentSplitRuleRepository
.findActiveApplicableRules(specialistId, profile.getSpecialistType());

if (rules.isEmpty()) {
throw new PaymentSplitRuleNotFoundException();
}

return rules.stream()
.min(Comparator.comparingInt(r -> r.getScope().getPriority()))
.orElseThrow(PaymentSplitRuleNotFoundException::new);
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.soupulsar.domain.exceptions;

public class PaymentSplitRuleNotFoundException extends RuntimeException {

public PaymentSplitRuleNotFoundException() {
super("No applicable payment split rule found");
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
package com.soupulsar.domain.repository;

import com.soupulsar.domain.model.enums.SpecialistType;
import com.soupulsar.domain.model.payment.PaymentSplitRule;

import java.util.List;
import java.util.Optional;
import java.util.UUID;

public interface PaymentSplitRuleRepository {

Optional<PaymentSplitRule> findById(UUID id);
PaymentSplitRule save(PaymentSplitRule paymentSplitRule);
List<PaymentSplitRule> findActiveApplicableRules(UUID specialistId, SpecialistType specialistType);

}
Original file line number Diff line number Diff line change
@@ -1,9 +1,21 @@
package com.soupulsar.infrastructure.persistence.repository;

import com.soupulsar.domain.model.enums.SpecialistType;
import com.soupulsar.infrastructure.persistence.entity.payment.PaymentSplitRuleEntity;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;

import java.util.List;
import java.util.UUID;

public interface PaymentSplitRuleJpaRepository extends JpaRepository<PaymentSplitRuleEntity, UUID> {

@Query("""
SELECT p FROM PaymentSplitRuleEntity p
WHERE p.active = true
AND (p.specialistId = :specialistId OR p.specialistId IS NULL)
AND (p.specialistType = :specialistType OR p.specialistType IS NULL)
""")
List<PaymentSplitRuleEntity> findActiveApplicableRules(UUID specialistId, SpecialistType specialistType);

}
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package com.soupulsar.infrastructure.persistence.repository.impl;

import com.soupulsar.domain.model.enums.SpecialistType;
import com.soupulsar.domain.model.payment.PaymentSplitRule;
import com.soupulsar.domain.repository.PaymentSplitRuleRepository;
import com.soupulsar.infrastructure.persistence.entity.payment.PaymentSplitRuleEntity;
import com.soupulsar.infrastructure.persistence.mapper.payment.PaymentSplitRuleMapper;
import com.soupulsar.infrastructure.persistence.repository.PaymentSplitRuleJpaRepository;
import lombok.RequiredArgsConstructor;

import java.util.List;
import java.util.Optional;
import java.util.UUID;

Expand All @@ -26,4 +28,15 @@ public PaymentSplitRule save(PaymentSplitRule paymentSplitRule) {
PaymentSplitRuleEntity saved = repository.save(entity);
return PaymentSplitRuleMapper.toModel(saved);
}

@Override
public List<PaymentSplitRule> findActiveApplicableRules(UUID specialistId, SpecialistType specialistType) {
var rules = repository.findActiveApplicableRules(specialistId, specialistType);
if (rules != null && !rules.isEmpty()) {
return rules.stream()
.map(PaymentSplitRuleMapper::toModel)
.toList();
}
return List.of();
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package com.soupulsar.modulith;
package com.soupulsar;

import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class SouPulsarModulithApplicationTests {
class SouPulsarApplicationTests {

@Test
void contextLoads() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
package com.soupulsar.modulith.auth.application.usecase;
package com.soupulsar.application.usecase;

import com.soupulsar.application.dto.request.AuthUserRequest;
import com.soupulsar.application.dto.response.AuthUserResponse;
import com.soupulsar.application.security.JwtService;
import com.soupulsar.application.security.PasswordHasher;
import com.soupulsar.application.usecase.AuthenticateUserUseCase;
import com.soupulsar.domain.exceptions.UserNotFoundException;
import com.soupulsar.domain.model.user.User;
import com.soupulsar.domain.model.enums.UserRole;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
package com.soupulsar.modulith.scheduling.application.usecase;
package com.soupulsar.application.usecase.availability;

import com.soupulsar.application.dto.request.CreateAvailabilityRequest;
import com.soupulsar.application.dto.response.CreateAvailabilityResponse;
import com.soupulsar.application.usecase.availability.CreateAvailabilityUseCase;
import com.soupulsar.domain.model.availability.Availability;
import com.soupulsar.domain.repository.AvailabilityRepository;
import org.junit.jupiter.api.BeforeEach;
Expand Down
Loading