diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5f4b8d9b980165d3b60c01525c5938a387c245c9..760807404ab5536e9affdb955539ee33ec787c6f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,22 @@
+## [1.0.75-RELEASE]
+### Added
+- MS-114/Export sale session data to CSV and upload to FTP server
+-
+### Changed
+- Changes in existing functionality.
+
+### Deprecated
+- Soon-to-be removed features.
+
+### Removed
+- Features that have been removed.
+
+### Fixed
+- Any bug fixes.
+
+### Security
+- Any security improvements.
+
## [1.0.74-RELEASE]
### Added
- MYD-739/Fix List with sale sessions stats
diff --git a/src/main/java/com/marketingconfort/mydressin/Application.java b/src/main/java/com/marketingconfort/mydressin/Application.java
index 2c6a023f09c6391ecf7dbf6a680540d5ee0fb0c0..f0c5a4ca698b99b28bb76aa7cfd4bbe596b75e9d 100644
--- a/src/main/java/com/marketingconfort/mydressin/Application.java
+++ b/src/main/java/com/marketingconfort/mydressin/Application.java
@@ -1,15 +1,18 @@
package com.marketingconfort.mydressin;
+import com.marketingconfort.mydressin.config.FTPConfig;
import com.marketingconfort.starter.core.config.props.CustomRestProperties;
import com.marketingconfort.starter.core.services.MCRestTemplateService;
import com.marketingconfort.starter.core.services.implementations.*;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.FilterType;
import org.springframework.context.annotation.Import;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
+import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication(scanBasePackages = "com.marketingconfort.mydressin")
@ComponentScan(basePackages = {
@@ -25,6 +28,7 @@ import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
"com.marketingconfort.mydressin.common.cart.models"
})
@Import({MCRestTemplateService.class, CustomRestProperties.class})
+@EnableScheduling
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
diff --git a/src/main/java/com/marketingconfort/mydressin/config/FTPConfig.java b/src/main/java/com/marketingconfort/mydressin/config/FTPConfig.java
new file mode 100644
index 0000000000000000000000000000000000000000..96cadec05614754f7fc35a0033df2609f464b171
--- /dev/null
+++ b/src/main/java/com/marketingconfort/mydressin/config/FTPConfig.java
@@ -0,0 +1,29 @@
+package com.marketingconfort.mydressin.config;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Primary;
+import org.springframework.stereotype.Component;
+
+
+@Primary
+@Component
+@AllArgsConstructor
+@NoArgsConstructor
+@Getter
+@Setter
+@ConfigurationProperties(prefix = "ftp")
+public class FTPConfig {
+
+
+ private String host;
+
+ private String username;
+
+ private String password;
+
+}
diff --git a/src/main/java/com/marketingconfort/mydressin/repositories/SaleSessionRepository.java b/src/main/java/com/marketingconfort/mydressin/repositories/SaleSessionRepository.java
index 15e4d76c6867796a1bcf13e8197ec72c67cbed79..268e9c0962a375672894462eacd9098e6643c40b 100644
--- a/src/main/java/com/marketingconfort/mydressin/repositories/SaleSessionRepository.java
+++ b/src/main/java/com/marketingconfort/mydressin/repositories/SaleSessionRepository.java
@@ -120,4 +120,7 @@ public interface SaleSessionRepository extends JpaRepository<SaleSession, Long>
@Param("name") String name ,
@Param("startDate") Date startDate ,
@Param("endDate") Date endDate);
+
+ @Query("SELECT s FROM SaleSession s WHERE CAST(s.startedDate AS date ) = :yesterdayDate ")
+ List<SaleSession> getAllYesterdaySaleSessions(@Param("yesterdayDate") Date yesterdayDate);
}
diff --git a/src/main/java/com/marketingconfort/mydressin/services/SaleSessionService.java b/src/main/java/com/marketingconfort/mydressin/services/SaleSessionService.java
index a0314fc418b52ec3a07796568b9b39deef2fde87..9959efd5d6f363a7382f494b636941e7b40b46d0 100644
--- a/src/main/java/com/marketingconfort/mydressin/services/SaleSessionService.java
+++ b/src/main/java/com/marketingconfort/mydressin/services/SaleSessionService.java
@@ -39,4 +39,6 @@ public interface SaleSessionService {
Page<SaleSessionDTO> getDeletedSaleSessionsPage(String name , String type, Date startDate, Date endDate,
int page, int size, String sortBy, String order);
List<String[]> getDeletedTypeCount(String name , String type, Date startDate, Date endDate);
+
+ void exportYesterdaySaleSessions();
}
diff --git a/src/main/java/com/marketingconfort/mydressin/services/impl/SaleSessionServiceImp.java b/src/main/java/com/marketingconfort/mydressin/services/impl/SaleSessionServiceImp.java
index c5e5fa66564ed586cfc52bbd21023af1c614ffe4..21041c2277379522bd38ebcae6571122147b0732 100644
--- a/src/main/java/com/marketingconfort/mydressin/services/impl/SaleSessionServiceImp.java
+++ b/src/main/java/com/marketingconfort/mydressin/services/impl/SaleSessionServiceImp.java
@@ -6,7 +6,7 @@ import com.marketingconfort.mydressin.common.cart.enumurations.ItemCartStatus;
import com.marketingconfort.mydressin.common.cart.enumurations.ItemSource;
import com.marketingconfort.mydressin.common.cart.enumurations.OrderStatus;
import com.marketingconfort.mydressin.common.cart.models.*;
-
+import com.marketingconfort.mydressin.config.FTPConfig;
import com.marketingconfort.mydressin.dtos.SaleSessionDTO;
import com.marketingconfort.mydressin.dtos.SessionOrderDTO;
import com.marketingconfort.mydressin.dtos.ItemRequestDTO;
@@ -18,18 +18,29 @@ import com.marketingconfort.mydressin.mappers.SaleSessionMapper;
import com.marketingconfort.mydressin.repositories.SaleSessionRepository;
import com.marketingconfort.mydressin.repositories.SessionOrderRepository;
import com.marketingconfort.mydressin.services.*;
+import com.opencsv.CSVWriter;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.net.ftp.FTPClient;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.scheduling.annotation.Async;
+import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
+import org.springframework.beans.factory.annotation.Value;
+import java.io.*;
+import java.time.LocalDate;
import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.time.ZoneId;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
@@ -38,6 +49,8 @@ import java.util.stream.Collectors;
@Service
@Slf4j
public class SaleSessionServiceImp implements SaleSessionService {
+ private static final Logger logger = LoggerFactory.getLogger(SaleSessionServiceImp.class);
+
private final SaleSessionRepository saleSessionRepository;
private final SaleSessionMapper saleSessionMapper;
private final ItemCartService itemCartService;
@@ -45,8 +58,11 @@ public class SaleSessionServiceImp implements SaleSessionService {
private final ProductStockService productStockService;
private final SessionOrderRepository orderRepository;
private final SessionOrderMapper sessionOrderMapper;
+ private final SessionOrderService sessionOrderService;
private final UnregisteredCartService unregisteredCartService;
private final SessionOrderRepository sessionOrderRepository;
+ private FTPConfig ftpConfig;
+
@Override
@@ -309,4 +325,124 @@ public class SaleSessionServiceImp implements SaleSessionService {
return stringList;
}
+ @Scheduled(cron = "0 0 7 * * ?")
+ @Override
+ public void exportYesterdaySaleSessions() {
+ LocalDate yesterday = LocalDate.now().minusDays(1);
+ DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
+ String formattedDate = yesterday.format(formatter);
+
+ logger.info("Starting export of yesterday's sale sessions for date: {}", formattedDate);
+
+ List<SaleSession> saleSessions = saleSessionRepository.getAllYesterdaySaleSessions(
+ Date.from(yesterday.atStartOfDay(ZoneId.systemDefault()).toInstant())
+ );
+ logger.info("Sale sessions count: {}", saleSessions.size());
+
+ String fileName = "sale_sessions_" + formattedDate + ".csv";
+ try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+ CSVWriter writer = new CSVWriter(new OutputStreamWriter(byteArrayOutputStream))) {
+
+ writer.writeNext(new String[]{
+ "idUtilisateur", "idCommande", "idSessionVente", "nameSession", "startDate", "expirationDate", "description",
+ "lastModification", "typeLive", "liveId", "statutPanier", "statutCommande", "prenom", "nom", "email", "telephone",
+ "nomUtilisateur", "nomProduit", "UGS", "quantite", "prixProduit", "montant", "dateCreationProduitCommande", "dateExpiration"
+ });
+
+ logger.info("CSV header written successfully for date: {}", formattedDate);
+
+ for (SaleSession saleSession : saleSessions) {
+ logger.debug("Processing SaleSession with ID: {}", saleSession.getId());
+ List<SessionOrderDTO> sessionOrderDTOS = sessionOrderService.getAllOrdersBySessionId(saleSession.getId());
+
+ for (SessionOrderDTO order : sessionOrderDTOS) {
+ List<String> row = new ArrayList<>();
+
+ String clientUid = order.getClient() != null ? String.valueOf(order.getClient().getUid()) : "N/A";
+ String firstName = order.getClient() != null ? order.getClient().getFirstName() : "N/A";
+ String lastName = order.getClient() != null ? order.getClient().getLastName() : "N/A";
+ String email = order.getClient() != null ? order.getClient().getEmail() : "N/A";
+ String phoneNumber = order.getClient() != null ? order.getClient().getPhoneNumber() : "N/A";
+ String pseudo = order.getClient() != null ? order.getClient().getPseudo() : "N/A";
+
+ row.add(clientUid);
+ row.add(String.valueOf(order.getId()));
+ row.add(String.valueOf(saleSession.getId()));
+ row.add(saleSession.getName());
+ row.add(saleSession.getStartedDate() != null ? saleSession.getStartedDate().toString() : "");
+ row.add(saleSession.getExpirationDate() != null ? saleSession.getExpirationDate().toString() : "");
+ row.add(saleSession.getDescription() != null ? saleSession.getDescription() : "");
+ row.add(saleSession.getLastModification() != null ? saleSession.getLastModification().toString() : "");
+ row.add(saleSession.getType() != null ? saleSession.getType().name() : "");
+ row.add(String.valueOf(saleSession.getLive()));
+ row.add(order.getStatus().name());
+ row.add(order.getStatus().name());
+ row.add(firstName);
+ row.add(lastName);
+ row.add(email);
+ row.add(phoneNumber);
+ row.add(pseudo);
+ row.add(order.getItemCartDTO() != null ? order.getItemCartDTO().getProduct().getName() : "");
+ row.add(order.getItemCartDTO() != null ? order.getItemCartDTO().getUgs() : "");
+ row.add(String.valueOf(order.getItemCartDTO() != null ? order.getItemCartDTO().getQuantity() : 0));
+ row.add(order.getCreatedDate() != null ? order.getCreatedDate().toString() : "");
+ row.add(String.valueOf(order.getPrice()));
+ row.add(String.valueOf(order.getPrice()));
+ row.add(order.getItemCartDTO() != null && order.getItemCartDTO().getExpirationDate() != null ? order.getItemCartDTO().getExpirationDate().toString() : "");
+
+ writer.writeNext(row.toArray(new String[0]));
+ }
+ }
+ writer.flush();
+ logger.info("Export completed successfully for date: {}", formattedDate);
+
+ // Now upload the data to the FTP server
+ uploadFileToFTPServer(fileName, byteArrayOutputStream.toByteArray());
+ } catch (IOException e) {
+ logger.error("Error occurred during export for date: {}", formattedDate, e);
+ }
+ }
+
+ private void uploadFileToFTPServer(String fileName, byte[] fileData) {
+ FTPClient ftpClient = new FTPClient();
+ try {
+ ftpClient.connect(ftpConfig.getHost());
+ ftpClient.login(ftpConfig.getUsername(), ftpConfig.getPassword());
+
+ logger.info("Connected to FTP server.");
+
+ ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
+ ftpClient.enterLocalPassiveMode();
+
+ logger.info("FTP Response Code: {}", ftpClient.getReplyCode());
+ logger.info("FTP Reply String: {}", ftpClient.getReplyString());
+
+ try (ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(fileData)) {
+ boolean done = ftpClient.storeFile("/sale_sessions/" + fileName, byteArrayInputStream);
+ if (done) {
+ logger.info("File uploaded successfully to FTP server.");
+ } else {
+ int replyCode = ftpClient.getReplyCode();
+ logger.error("Failed to upload file, FTP server reply: {}", replyCode);
+ }
+ }
+
+ ftpClient.logout();
+ logger.info("Logged out from FTP server.");
+
+ } catch (IOException e) {
+ logger.error("Error occurred while uploading file to FTP server: ", e);
+ } finally {
+ try {
+ if (ftpClient.isConnected()) {
+ ftpClient.disconnect();
+ }
+ } catch (IOException e) {
+ logger.error("Error occurred while disconnecting from FTP server: ", e);
+ }
+ }
+ }
+
+
}
+