From 35895ea634ad24512f6d867afde34b7434e50afb Mon Sep 17 00:00:00 2001
From: anasElhaddad <anas.elhaddad@marketingconfort.com>
Date: Wed, 30 Apr 2025 15:15:51 +0000
Subject: [PATCH 1/2] Export sale session data to CSV and upload to FTP server

---
 CHANGELOG.md                                  |  19 +++
 .../mydressin/Application.java                |   4 +
 .../mydressin/config/FTPConfig.java           |  29 ++++
 .../repositories/SaleSessionRepository.java   |   3 +
 .../services/SaleSessionService.java          |   2 +
 .../services/impl/SaleSessionServiceImp.java  | 138 +++++++++++++++++-
 6 files changed, 194 insertions(+), 1 deletion(-)
 create mode 100644 src/main/java/com/marketingconfort/mydressin/config/FTPConfig.java

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5f4b8d9..7608074 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 2c6a023..f0c5a4c 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 0000000..96cadec
--- /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 15e4d76..268e9c0 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 a0314fc..9959efd 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 c5e5fa6..110b796 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(3);
+        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);
+            }
+        }
+    }
+
+
 }
+
-- 
GitLab


From 835b6dcf410acc0175596f0ebd0077b125d8172a Mon Sep 17 00:00:00 2001
From: anasElhaddad <anas.elhaddad@marketingconfort.com>
Date: Wed, 30 Apr 2025 15:20:13 +0000
Subject: [PATCH 2/2] Export sale session data to CSV and upload to FTP server

---
 .../mydressin/services/impl/SaleSessionServiceImp.java          | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

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 110b796..21041c2 100644
--- a/src/main/java/com/marketingconfort/mydressin/services/impl/SaleSessionServiceImp.java
+++ b/src/main/java/com/marketingconfort/mydressin/services/impl/SaleSessionServiceImp.java
@@ -328,7 +328,7 @@ public class SaleSessionServiceImp implements SaleSessionService {
     @Scheduled(cron = "0 0 7 * * ?")
     @Override
     public void exportYesterdaySaleSessions() {
-        LocalDate yesterday = LocalDate.now().minusDays(3);
+        LocalDate yesterday = LocalDate.now().minusDays(1);
         DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
         String formattedDate = yesterday.format(formatter);
 
-- 
GitLab