176 lines
8.6 KiB
Java
176 lines
8.6 KiB
Java
package fr.titionfire.ffsaf.domain.service;
|
|
|
|
import fr.titionfire.ffsaf.data.model.CheckoutModel;
|
|
import fr.titionfire.ffsaf.data.model.LogModel;
|
|
import fr.titionfire.ffsaf.data.repository.CheckoutRepository;
|
|
import fr.titionfire.ffsaf.data.repository.LicenceRepository;
|
|
import fr.titionfire.ffsaf.rest.client.HelloAssoService;
|
|
import fr.titionfire.ffsaf.rest.client.dto.CheckoutIntentsRequest;
|
|
import fr.titionfire.ffsaf.rest.client.dto.CheckoutIntentsResponse;
|
|
import fr.titionfire.ffsaf.rest.client.dto.CheckoutMetadata;
|
|
import fr.titionfire.ffsaf.rest.exception.DInternalError;
|
|
import fr.titionfire.ffsaf.utils.SecurityCtx;
|
|
import fr.titionfire.ffsaf.utils.Utils;
|
|
import io.quarkus.hibernate.reactive.panache.Panache;
|
|
import io.quarkus.hibernate.reactive.panache.common.WithSession;
|
|
import io.quarkus.scheduler.Scheduled;
|
|
import io.smallrye.mutiny.Uni;
|
|
import jakarta.enterprise.context.ApplicationScoped;
|
|
import jakarta.inject.Inject;
|
|
import jakarta.ws.rs.core.Response;
|
|
import org.eclipse.microprofile.config.inject.ConfigProperty;
|
|
import org.eclipse.microprofile.rest.client.inject.RestClient;
|
|
import org.hibernate.reactive.mutiny.Mutiny;
|
|
|
|
import java.util.Calendar;
|
|
import java.util.Date;
|
|
import java.util.List;
|
|
|
|
@WithSession
|
|
@ApplicationScoped
|
|
public class CheckoutService {
|
|
|
|
@Inject
|
|
CheckoutRepository repository;
|
|
|
|
@Inject
|
|
LicenceRepository licenceRepository;
|
|
|
|
@Inject
|
|
MembreService membreService;
|
|
|
|
@Inject
|
|
LicenceService licenceService;
|
|
|
|
@Inject
|
|
LoggerService ls;
|
|
|
|
@RestClient
|
|
HelloAssoService helloAssoService;
|
|
|
|
@ConfigProperty(name = "frontRootUrl")
|
|
String frontRootUrl;
|
|
|
|
@ConfigProperty(name = "unitLicencePrice")
|
|
int unitLicencePrice;
|
|
|
|
@ConfigProperty(name = "helloasso.organizationSlug")
|
|
String organizationSlug;
|
|
|
|
public Uni<Boolean> canDeleteLicence(long id) {
|
|
return repository.find("?1 IN licenseIds", id).count().map(count -> count == 0);
|
|
}
|
|
|
|
public Uni<String> create(List<Long> ids, SecurityCtx securityCtx) {
|
|
return membreService.getByAccountId(securityCtx.getSubject())
|
|
.call(membreModel -> Mutiny.fetch(membreModel.getClub()))
|
|
.chain(membreModel -> {
|
|
CheckoutModel model = new CheckoutModel();
|
|
model.setMembre(membreModel);
|
|
model.setLicenseIds(ids);
|
|
model.setPaymentStatus(CheckoutModel.PaymentStatus.UNKNOW);
|
|
|
|
return Panache.withTransaction(() -> repository.persist(model));
|
|
})
|
|
.chain(checkoutModel -> {
|
|
CheckoutIntentsRequest request = new CheckoutIntentsRequest();
|
|
request.setTotalAmount(unitLicencePrice * checkoutModel.getLicenseIds().size());
|
|
request.setInitialAmount(unitLicencePrice * checkoutModel.getLicenseIds().size());
|
|
request.setItemName("%d licences %d-%d pour %s".formatted(checkoutModel.getLicenseIds().size(),
|
|
Utils.getSaison(), Utils.getSaison() + 1, checkoutModel.getMembre().getClub().getName()));
|
|
request.setBackUrl(frontRootUrl + "/club/member/pay");
|
|
request.setErrorUrl(frontRootUrl + "/club/member/pay/error");
|
|
request.setReturnUrl(frontRootUrl + "/club/member/pay/return");
|
|
request.setContainsDonation(false);
|
|
request.setPayer(new CheckoutIntentsRequest.Payer(checkoutModel.getMembre().getFname(),
|
|
checkoutModel.getMembre().getLname(), checkoutModel.getMembre().getEmail()));
|
|
request.setMetadata(new CheckoutMetadata(checkoutModel.getId()));
|
|
|
|
return helloAssoService.checkout(organizationSlug, request)
|
|
.call(response -> {
|
|
checkoutModel.setCheckoutId(response.getId());
|
|
return Panache.withTransaction(() -> repository.persist(checkoutModel));
|
|
});
|
|
})
|
|
.onFailure().transform(t -> new DInternalError(t.getMessage()))
|
|
.map(CheckoutIntentsResponse::getRedirectUrl);
|
|
}
|
|
|
|
public Uni<Response> paymentStatusChange(String state, CheckoutMetadata metadata) {
|
|
return repository.findById(metadata.getCheckoutDBId())
|
|
.chain(checkoutModel -> {
|
|
CheckoutModel.PaymentStatus newStatus = CheckoutModel.PaymentStatus.valueOf(state.toUpperCase());
|
|
|
|
Uni<?> uni = Uni.createFrom().nullItem();
|
|
|
|
if (checkoutModel.getPaymentStatus().equals(newStatus))
|
|
return uni;
|
|
|
|
if (newStatus.equals(CheckoutModel.PaymentStatus.AUTHORIZED)) {
|
|
for (Long id : checkoutModel.getLicenseIds()) {
|
|
uni = uni.chain(__ -> licenceRepository.findById(id)
|
|
.onFailure().recoverWithNull()
|
|
.call(licenceModel -> {
|
|
if (licenceModel == null) {
|
|
ls.logAnonymous(LogModel.ActionType.UPDATE, LogModel.ObjectType.Licence,
|
|
"Fail to save payment for licence (checkout n°" + checkoutModel.getCheckoutId() + ")",
|
|
"", id);
|
|
return Uni.createFrom().nullItem();
|
|
}
|
|
|
|
ls.logUpdateAnonymous("Paiement de la licence", licenceModel);
|
|
licenceModel.setPay(true);
|
|
|
|
if (licenceModel.getCertificate() != null && licenceModel.getCertificate()
|
|
.length() > 3) {
|
|
if (!licenceModel.isValidate())
|
|
ls.logUpdateAnonymous("Validation automatique de la licence",
|
|
licenceModel);
|
|
return licenceService.validateLicences(licenceModel);
|
|
} else {
|
|
return Panache.withTransaction(
|
|
() -> licenceRepository.persist(licenceModel));
|
|
}
|
|
}));
|
|
}
|
|
} else if (checkoutModel.getPaymentStatus().equals(CheckoutModel.PaymentStatus.AUTHORIZED)) {
|
|
for (Long id : checkoutModel.getLicenseIds()) {
|
|
uni = uni.chain(__ -> licenceRepository.findById(id)
|
|
.onFailure().recoverWithNull()
|
|
.call(licenceModel -> {
|
|
if (licenceModel == null)
|
|
return Uni.createFrom().nullItem();
|
|
|
|
ls.logUpdateAnonymous("Annulation automatique du paiement de la licence",
|
|
licenceModel);
|
|
licenceModel.setPay(false);
|
|
if (licenceModel.isValidate())
|
|
ls.logUpdateAnonymous(
|
|
"Annulation automatique de la validation de la licence",
|
|
licenceModel);
|
|
licenceModel.setValidate(false);
|
|
return Panache.withTransaction(() -> licenceRepository.persist(licenceModel));
|
|
}));
|
|
}
|
|
}
|
|
uni = uni.call(__ -> ls.append());
|
|
|
|
checkoutModel.setPaymentStatus(newStatus);
|
|
return uni.chain(__ -> Panache.withTransaction(() -> repository.persist(checkoutModel)));
|
|
})
|
|
.onFailure().invoke(Throwable::printStackTrace)
|
|
.map(__ -> Response.ok().build());
|
|
}
|
|
|
|
@Scheduled(cron = "0 0 * * * ?")
|
|
Uni<Void> everyHours() {
|
|
Calendar calendar = Calendar.getInstance();
|
|
calendar.add(Calendar.HOUR, -1);
|
|
Date dateLimit = calendar.getTime();
|
|
|
|
return repository.delete("creationDate < ?1 AND (checkoutId IS NULL OR paymentStatus = ?2)", dateLimit,
|
|
CheckoutModel.PaymentStatus.UNKNOW)
|
|
.map(__ -> null);
|
|
}
|
|
}
|