diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/controller/admin/PurchaseOrderController.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/controller/admin/PurchaseOrderController.java index 90a00a67b..922f776e3 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/controller/admin/PurchaseOrderController.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/controller/admin/PurchaseOrderController.java @@ -13,6 +13,7 @@ import org.jeecg.common.aspect.annotation.AutoLog; import org.jeecg.common.system.query.QueryGenerator; import org.jeecg.common.system.vo.LoginUser; import org.jeecg.common.util.oConvertUtils; +import org.jeecg.modules.business.controller.UserException; import org.jeecg.modules.business.domain.purchase.invoice.InvoiceData; import org.jeecg.modules.business.entity.*; import org.jeecg.modules.business.service.*; @@ -421,7 +422,7 @@ public class PurchaseOrderController { */ @AutoLog(value = "商品采购清单-通过客户id查询") @RequestMapping(value = "/admin/loadInventory") - public Result loadInventory(@RequestParam(name = "id") String clientId) { + public Result loadInventory(@RequestParam(name = "id") String clientId) throws UserException { Client client = clientService.getById(clientId); ClientInfo clientInfo = new ClientInfo(client); List importedInventories = importedInventoryService.selectByClientId(clientId); diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/controller/admin/UserClientController.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/controller/admin/UserClientController.java index e73f18c48..586af778a 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/controller/admin/UserClientController.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/controller/admin/UserClientController.java @@ -35,7 +35,8 @@ public class UserClientController { public Result getClientByUserId() { LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal(); String userId = loginUser.getId(); - userId = "1708866308713140225"; +// userId = "1708866308713140225"; //EP +// userId = "1721929497801580546"; //ND Client client = userClientService.getClientByUserId(userId); if(client == null) { List sysRoles = sysUserRoleService.getUserRole(userId); diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/controller/admin/shippingInvoice/InvoiceController.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/controller/admin/shippingInvoice/InvoiceController.java index 5e651abe1..0e87dfb7b 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/controller/admin/shippingInvoice/InvoiceController.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/controller/admin/shippingInvoice/InvoiceController.java @@ -31,6 +31,7 @@ import org.springframework.web.bind.annotation.*; import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer; import javax.mail.Authenticator; +import javax.mail.MessagingException; import javax.mail.PasswordAuthentication; import javax.mail.Session; import javax.servlet.http.HttpServletRequest; @@ -235,6 +236,8 @@ public class InvoiceController { } catch (IOException | ParseException e) { log.error(e.getMessage()); return Result.error("Sorry, server error, please try later"); + } catch (MessagingException e) { + throw new RuntimeException(e); } } @@ -280,6 +283,8 @@ public class InvoiceController { } catch (IOException | ParseException e) { log.error(e.getMessage()); return Result.error("Sorry, server error, please try later"); + } catch (MessagingException e) { + throw new RuntimeException(e); } } @@ -411,7 +416,7 @@ public class InvoiceController { clientId = clientIDCodeMap.get(estimation.getCode()); } else { - clientId = clientService.getClientByInternalCode(estimation.getCode()); + clientId = clientService.getClientIdByCode(estimation.getCode()); clientIDCodeMap.put(estimation.getCode(), clientId); } if (estimation.getIsCompleteInvoice().equals("1")) { @@ -453,7 +458,7 @@ public class InvoiceController { }); for(Map.Entry> entry : estimationClientMap.entrySet()) { String code = entry.getKey(); - String clientId = clientService.getClientByInternalCode(code); + String clientId = clientService.getClientIdByCode(code); List shops = new ArrayList<>(); int ordersToProcess = 0; int processedOrders = 0; diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/controller/admin/shippingInvoice/ShippingInvoiceController.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/controller/admin/shippingInvoice/ShippingInvoiceController.java index 8918e4f01..24f39bd6d 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/controller/admin/shippingInvoice/ShippingInvoiceController.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/controller/admin/shippingInvoice/ShippingInvoiceController.java @@ -75,6 +75,8 @@ public class ShippingInvoiceController { @Autowired private IPlatformOrderService platformOrderService; @Autowired + private IPurchaseOrderService purchaseOrderService; + @Autowired private ISavRefundService savRefundService; @Autowired private IShippingInvoiceService shippingInvoiceService; @@ -510,6 +512,7 @@ public class ShippingInvoiceController { log.info("Cancelling invoice number : {}", invoiceNumber); platformOrderContentService.cancelInvoice(invoiceNumber); platformOrderService.cancelInvoice(invoiceNumber); + purchaseOrderService.cancelInvoice(invoiceNumber); savRefundService.cancelInvoice(invoiceNumber); shippingInvoiceService.delMain(id); log.info("Updating balance ..."); @@ -571,6 +574,7 @@ public class ShippingInvoiceController { public Result cancelBatchInvoice(@RequestParam("ids") List ids, @RequestParam("invoiceNumbers") List invoiceNumbers, @RequestParam("clientIds") List clientIds) { log.info("Cancelling invoices : {}", invoiceNumbers); + purchaseOrderService.cancelBatchInvoice(invoiceNumbers); platformOrderContentService.cancelBatchInvoice(invoiceNumbers); platformOrderService.cancelBatchInvoice(invoiceNumbers); savRefundService.cancelBatchInvoice(invoiceNumbers); diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/controller/client/ClientPlatformOrderController.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/controller/client/ClientPlatformOrderController.java index 07fef63ac..0b2aeb697 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/controller/client/ClientPlatformOrderController.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/controller/client/ClientPlatformOrderController.java @@ -12,6 +12,7 @@ import org.jeecg.common.aspect.annotation.AutoLog; import org.jeecg.common.system.query.QueryGenerator; import org.jeecg.common.system.vo.LoginUser; import org.jeecg.common.util.oConvertUtils; +import org.jeecg.modules.business.controller.UserException; import org.jeecg.modules.business.entity.ClientPlatformOrderContent; import org.jeecg.modules.business.entity.PlatformOrder; import org.jeecg.modules.business.entity.PlatformOrderContent; @@ -192,7 +193,7 @@ public class ClientPlatformOrderController { notes = "Compute order statistic data of platform orders indicated by its identifier." ) @PostMapping(value = "/computeInfo", consumes = "application/json", produces = "application/json") - public Result queryOrdersStatisticInfo(@RequestBody List orderIds) { + public Result queryOrdersStatisticInfo(@RequestBody List orderIds) throws UserException { log.info("Calculating statistic information for orders: {}", orderIds); OrdersStatisticData ordersData = platformOrderService.getPlatformOrdersStatisticData(orderIds); log.info("Got statistic information: {}", ordersData); @@ -212,7 +213,7 @@ public class ClientPlatformOrderController { "client confirm information." ) @PostMapping(value = "/placeOrder", consumes = "application/json", produces = "application/json") - public Result placeOrder(@RequestBody List orderIds) { + public Result placeOrder(@RequestBody List orderIds) throws UserException { log.info("One client place a purchase order"); PurchaseConfirmation d = platformOrderService.confirmPurchaseByPlatformOrder(orderIds); log.info(d.toString()); @@ -226,7 +227,7 @@ public class ClientPlatformOrderController { * @return confirmation. */ @PostMapping(value = "/adjustOrder", consumes = "application/json", produces = "application/json") - public Result adjustOrder(@RequestBody List skuQuantities) { + public Result adjustOrder(@RequestBody List skuQuantities) throws UserException { log.info("One client adjust its purchase order"); log.info("Content: {}", skuQuantities); PurchaseConfirmation d = platformOrderService.confirmPurchaseBySkuQuantity(skuQuantities); diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/controller/client/ClientPurchaseController.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/controller/client/ClientPurchaseController.java index 9aa64551b..bca9873bb 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/controller/client/ClientPurchaseController.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/controller/client/ClientPurchaseController.java @@ -6,6 +6,7 @@ import io.swagger.annotations.ApiOperation; import lombok.extern.slf4j.Slf4j; import org.jeecg.common.api.vo.Result; import org.jeecg.common.aspect.annotation.AutoLog; +import org.jeecg.modules.business.controller.UserException; import org.jeecg.modules.business.controller.client.requestParams.PurchaseRequest; import org.jeecg.modules.business.entity.PurchaseOrder; import org.jeecg.modules.business.service.IPurchaseOrderService; @@ -64,7 +65,7 @@ public class ClientPurchaseController { @AutoLog(value = "商品采购订单-添加") @ApiOperation(value = "商品采购订单-添加", notes = "商品采购订单-添加") @PostMapping(value = "/add") - public Result addPurchaseOrder(@RequestBody PurchaseRequest purchaseRequest) { + public Result addPurchaseOrder(@RequestBody PurchaseRequest purchaseRequest) throws UserException { String id = purchaseOrderService.addPurchase( purchaseRequest.getSkuQuantity(), purchaseRequest.getPlatformOrderIDList() diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/controller/client/TransactionController.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/controller/client/TransactionController.java index 371b4db96..f44f7d8e9 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/controller/client/TransactionController.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/controller/client/TransactionController.java @@ -3,7 +3,9 @@ package org.jeecg.modules.business.controller.client; import cn.hutool.core.date.DateTime; import io.swagger.annotations.Api; import lombok.extern.slf4j.Slf4j; +import org.jeecg.common.api.dto.message.TemplateMessageDTO; import org.jeecg.common.api.vo.Result; +import org.jeecg.common.system.api.ISysBaseAPI; import org.jeecg.modules.business.domain.shippingInvoice.ShippingInvoiceFactory; import org.jeecg.modules.business.entity.PlatformOrder; import org.jeecg.modules.business.entity.PlatformOrderContent; @@ -13,6 +15,7 @@ import org.jeecg.modules.business.service.*; import org.jeecg.modules.business.vo.Estimation; import org.jeecg.modules.business.vo.ShippingFeesEstimation; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; @@ -28,6 +31,8 @@ import java.util.stream.Collectors; @RequestMapping("/transaction") @Slf4j public class TransactionController { + @Autowired + private EmailService emailService; @Autowired private TransactionMapper transactionMapper; @Autowired @@ -68,6 +73,13 @@ public class TransactionController { ISavRefundWithDetailService savRefundWithDetailService; @Autowired ISavRefundService savRefundService; + @Autowired + private ISysBaseAPI ISysBaseApi; + @Autowired + Environment env; + + private final String SECTION_START = "
    "; + private final String SECTION_END = "
"; @GetMapping(value="/list") public Result list() { return Result.ok(transactionMapper.list()); @@ -91,7 +103,7 @@ public class TransactionController { ShippingInvoiceFactory factory = new ShippingInvoiceFactory( platformOrderService, clientMapper, shopMapper, logisticChannelMapper, logisticChannelPriceMapper, platformOrderContentService, skuDeclaredValueService, countryService, exchangeRatesMapper, - purchaseOrderService, purchaseOrderContentMapper, skuPromotionHistoryMapper, savRefundService, savRefundWithDetailService); + purchaseOrderService, purchaseOrderContentMapper, skuPromotionHistoryMapper, savRefundService, savRefundWithDetailService, emailService, env); List shippingFeesEstimations = factory.getEstimations(clientId, orderIds, errorMessages); if(shippingFeesEstimations.isEmpty()) return Result.OK("No estimation found."); @@ -131,6 +143,28 @@ public class TransactionController { System.out.println("Purchase Fee " + currency + " : " + purchaseEstimation); System.out.println("Shipping Fee " + currency + " : " + shippingFeesEstimation); } + // system notification + String errors = SECTION_START; + int max_entries = 100; + int current_page = 0; + int total_page = (int) Math.ceil((double) errorMessages.size() /max_entries); + for(int i = 1; i <= errorMessages.size(); i++) { + if(i%max_entries == 1) { + errors = SECTION_START; + current_page++; + } + errors = errors.concat("
  • " + i + " : " + errorMessages.get(i-1) +"
  • "); + if(i%max_entries==0 || i == errorMessages.size()) { + errors = errors.concat(SECTION_END); + Map param = new HashMap<>(); + param.put("nb_entries", String.valueOf(errorMessages.size())); + param.put("errors", errors); + param.put("current_page", String.valueOf(current_page)); + param.put("total_page", String.valueOf(total_page)); + TemplateMessageDTO message = new TemplateMessageDTO("admin", "Gauthier", "Expenses Overview Errors", param, "expenses_overview_errors"); + ISysBaseApi.sendTemplateAnnouncement(message); + } + } return Result.ok(new Estimation(shippingFeesEstimation, purchaseEstimation, currency, errorMessages, shopIds, new DateTime(startDate).toString(), new DateTime(endDate).toString(), isCompleteInvoiceReady)); } } diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/job/ConfirmedClientsInvoicingJob.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/job/ConfirmedClientsInvoicingJob.java new file mode 100644 index 000000000..ff24d0493 --- /dev/null +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/job/ConfirmedClientsInvoicingJob.java @@ -0,0 +1,161 @@ +package org.jeecg.modules.business.domain.job; + +import freemarker.template.Template; +import lombok.extern.slf4j.Slf4j; +import org.jeecg.modules.business.entity.Client; +import org.jeecg.modules.business.entity.SavRefundWithDetail; +import org.jeecg.modules.business.service.*; +import org.jeecg.modules.business.vo.BalanceData; +import org.jeecg.modules.business.vo.FactureDetail; +import org.jeecg.modules.business.vo.InvoiceMetaData; +import org.quartz.Job; +import org.quartz.JobExecutionContext; +import org.quartz.JobExecutionException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; +import org.springframework.ui.freemarker.FreeMarkerTemplateUtils; +import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer; + +import javax.mail.Authenticator; +import javax.mail.MessagingException; +import javax.mail.PasswordAuthentication; +import javax.mail.Session; +import java.io.IOException; +import java.math.BigDecimal; +import java.time.LocalDate; +import java.util.*; +import java.util.stream.Collectors; + +@Slf4j +public class ConfirmedClientsInvoicingJob implements Job { + @Autowired + private IBalanceService balanceService; + @Autowired + private IClientService clientService; + @Autowired + private EmailService emailService; + @Autowired + private PlatformOrderShippingInvoiceService platformOrderShippingInvoiceService; + @Autowired + private ISavRefundWithDetailService savRefundWithDetailService; + + @Autowired + Environment env; + @Autowired + private FreeMarkerConfigurer freemarkerConfigurer; + @Override + public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { + log.info("Confirmed clients Invoicing Job started ..."); + List confirmedClients = clientService.getClientsByType("confirmed"); + List clients = new ArrayList<>(); + List balanceDataList = new ArrayList<>(); + List shippingBalanceDataList = new ArrayList<>(); + List completeBalanceDataList = new ArrayList<>(); + for(Client client : confirmedClients) { + BigDecimal balance = balanceService.getBalanceByClientIdAndCurrency(client.getId(), client.getCurrency()); + if(balance.compareTo(BigDecimal.ZERO) > 0) { + clients.add(client); + balanceDataList.add(new BalanceData(client, client.getCurrency(), balance)); + if(client.getIsCompleteInvoice().equals("0")) { + shippingBalanceDataList.add(new BalanceData(client, client.getCurrency(), balance)); + } + else { + completeBalanceDataList.add(new BalanceData(client, client.getCurrency(), balance)); + } + } + } + + log.info("shipping clients list size : " + shippingBalanceDataList.size()); + log.info("complete clients list size : " + completeBalanceDataList.size()); + List invoiceList = new ArrayList<>(); + // we need to make sure that the client has enough balance to be invoiced + // step 1 : get the list of clients that have enough positive balance + // step 2 : calculer au pro rata le montant de la facture pour qu'elle ne dépasse pas le solde du client + // step 3 : update balance + // step 4 : generate invoice + // step 5 : send mail to client if balance is low + if(!shippingBalanceDataList.isEmpty()) { + log.info("Making shipping invoice for clients : {}", shippingBalanceDataList); + invoiceList = new ArrayList<>(platformOrderShippingInvoiceService.breakdownInvoiceClientByTypeAndBalance(shippingBalanceDataList, 0)); + } + if(!completeBalanceDataList.isEmpty()) { + log.info("Making complete shipping invoice for clients : {}", completeBalanceDataList); + invoiceList.addAll(platformOrderShippingInvoiceService.breakdownInvoiceClientByTypeAndBalance(completeBalanceDataList, 1)); + } + if(invoiceList.isEmpty()) { + log.info("Nothing to invoice."); + return; + } + + List metaDataErrorList = new ArrayList<>(); + List invoicedMetaDataList = new ArrayList<>(); // list of invoice metadata that has been invoiced + log.info("Generating detail files ...0/{}", invoiceList.size()); + int cpt = 1; + for(InvoiceMetaData metaData: invoiceList){ + if(metaData.getInvoiceCode().equals("error")) { + metaDataErrorList.add(metaData); + } + else { + invoicedMetaDataList.add(metaData); + List factureDetails = platformOrderShippingInvoiceService.getInvoiceDetail(metaData.getInvoiceCode()); + List refunds = savRefundWithDetailService.getRefundsByInvoiceNumber(metaData.getInvoiceCode()); + try { + platformOrderShippingInvoiceService.exportToExcel(factureDetails, refunds, metaData.getInvoiceCode(), metaData.getInvoiceEntity(), metaData.getInternalCode()); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + log.info("Generating detail files ...{}/{}", cpt++, invoiceList.size()); + } + if(!metaDataErrorList.isEmpty()) { + String subject = "[" + LocalDate.now() + "] Confirmed clients invoicing job report"; + String destEmail = env.getProperty("spring.mail.username"); + String templateName = "vipInvoicingJobReport.ftl"; + Map templateModel = new HashMap<>(); + templateModel.put("job", "Confirmed clients"); + templateModel.put("errors", metaDataErrorList); + try { + emailService.newSendSimpleMessage(destEmail, subject, templateName, templateModel); + } catch (MessagingException e) { + throw new RuntimeException(e); + } + } + // emailing for low balance clients + List lowBalanceDataList = balanceService.getLowBalanceClients(invoicedMetaDataList); + //todo : send mail to clients in prod + if(!lowBalanceDataList.isEmpty()) { + for(BalanceData data : lowBalanceDataList) { + log.info("Low balance client : {}", data.getClient().getInternalCode()); + String subject = "[" + LocalDate.now() + "] WIA App low balance notification"; + String destEmail = env.getProperty("spring.mail.username"); + Properties prop = emailService.getMailSender(); + Map templateModel = new HashMap<>(); + templateModel.put("firstname", data.getClient().getFirstName()); + templateModel.put("lastname", data.getClient().getSurname()); + templateModel.put("balance", data.getBalance()); + templateModel.put("currency", data.getCurrency()); + templateModel.put("clientCategory", "confirmed"); + + Session session = Session.getInstance(prop, new Authenticator() { + @Override + protected PasswordAuthentication getPasswordAuthentication() { + return new PasswordAuthentication(env.getProperty("spring.mail.username"), env.getProperty("spring.mail.password")); + } + }); + try { + freemarkerConfigurer = emailService.freemarkerClassLoaderConfig(); + Template freemarkerTemplate = freemarkerConfigurer.getConfiguration() + .getTemplate("client/lowBalanceNotification.ftl"); + String htmlBody = FreeMarkerTemplateUtils.processTemplateIntoString(freemarkerTemplate, templateModel); + emailService.sendSimpleMessage(destEmail, subject, htmlBody, session); + //todo : update balance_notification date and reason + log.info("Mail sent successfully !"); + } catch (Exception e) { + log.error("Error while sending low balance notification mail in VipInvoicingJob : ", e); + e.printStackTrace(); + } + } + } + log.info("Confirmed clients invoicing job finished."); + } +} diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/job/VipInvoicingJob.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/job/VipInvoicingJob.java index 57486ca21..6c6bf7b57 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/job/VipInvoicingJob.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/job/VipInvoicingJob.java @@ -2,9 +2,9 @@ package org.jeecg.modules.business.domain.job; import freemarker.template.Template; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.tuple.Pair; import org.jeecg.modules.business.entity.*; import org.jeecg.modules.business.service.*; +import org.jeecg.modules.business.vo.BalanceData; import org.jeecg.modules.business.vo.FactureDetail; import org.jeecg.modules.business.vo.InvoiceMetaData; import org.quartz.Job; @@ -19,12 +19,15 @@ import javax.mail.Authenticator; import javax.mail.PasswordAuthentication; import javax.mail.Session; import java.io.IOException; +import java.math.BigDecimal; import java.time.LocalDate; import java.util.*; import java.util.stream.Collectors; @Slf4j public class VipInvoicingJob implements Job { + @Autowired + private IBalanceService balanceService; @Autowired private IClientService clientService; @Autowired @@ -40,7 +43,7 @@ public class VipInvoicingJob implements Job { private FreeMarkerConfigurer freemarkerConfigurer; @Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { - log.info("VIP Invoicing Job executed."); + log.info("VIP Invoicing Job started ..."); List clients = clientService.getClientsByType("vip"); List shippingClientIds = clients.stream().filter(client -> client.getIsCompleteInvoice().equals("0")).map(Client::getId).collect(Collectors.toList()); List completeClientIds = clients.stream().filter(client -> client.getIsCompleteInvoice().equals("1")).map(Client::getId).collect(Collectors.toList()); @@ -62,6 +65,7 @@ public class VipInvoicingJob implements Job { } List metaDataErrorList = new ArrayList<>(); + List invoicedMetaDataList = new ArrayList<>(); // list of invoice meta data that has been invoiced log.info("Generating detail files ...0/{}", invoiceList.size()); int cpt = 1; for(InvoiceMetaData metaData: invoiceList){ @@ -69,6 +73,7 @@ public class VipInvoicingJob implements Job { metaDataErrorList.add(metaData); } else { + invoicedMetaDataList.add(metaData); List factureDetails = platformOrderShippingInvoiceService.getInvoiceDetail(metaData.getInvoiceCode()); List refunds = savRefundWithDetailService.getRefundsByInvoiceNumber(metaData.getInvoiceCode()); try { @@ -84,6 +89,7 @@ public class VipInvoicingJob implements Job { String destEmail = env.getProperty("spring.mail.username"); Properties prop = emailService.getMailSender(); Map templateModel = new HashMap<>(); + templateModel.put("job", "VIP"); templateModel.put("errors", metaDataErrorList); Session session = Session.getInstance(prop, new Authenticator() { @@ -104,6 +110,43 @@ public class VipInvoicingJob implements Job { e.printStackTrace(); } } + // emailing for low balance clients + List lowBalanceDataList = balanceService.getLowBalanceClients(invoicedMetaDataList); + + if(!lowBalanceDataList.isEmpty()) { + for(BalanceData data : lowBalanceDataList) { + log.info("Low balance client : {}", data.getClient().getInternalCode()); + String subject = "[" + LocalDate.now() + "] WIA App low balance notification"; + // TODO : change destEmail to client email for prod + String destEmail = env.getProperty("spring.mail.username"); + Properties prop = emailService.getMailSender(); + Map templateModel = new HashMap<>(); + templateModel.put("firstname", data.getClient().getFirstName()); + templateModel.put("lastname", data.getClient().getSurname()); + templateModel.put("balance", data.getBalance()); + templateModel.put("currency", data.getCurrency()); + templateModel.put("clientCategory", "vip"); + + Session session = Session.getInstance(prop, new Authenticator() { + @Override + protected PasswordAuthentication getPasswordAuthentication() { + return new PasswordAuthentication(env.getProperty("spring.mail.username"), env.getProperty("spring.mail.password")); + } + }); + try { + freemarkerConfigurer = emailService.freemarkerClassLoaderConfig(); + Template freemarkerTemplate = freemarkerConfigurer.getConfiguration() + .getTemplate("client/lowBalanceNotification.ftl"); + String htmlBody = FreeMarkerTemplateUtils.processTemplateIntoString(freemarkerTemplate, templateModel); + emailService.sendSimpleMessage(destEmail, subject, htmlBody, session); + //todo : update balance_notification date and reason + log.info("Mail sent successfully !"); + } catch (Exception e) { + log.error("Error while sending low balance notification mail in VipInvoicingJob : ", e); + e.printStackTrace(); + } + } + } log.info("VIP invoicing job finished."); } } diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/shippingInvoice/ShippingInvoiceFactory.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/shippingInvoice/ShippingInvoiceFactory.java index 70d21e351..1079c2753 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/shippingInvoice/ShippingInvoiceFactory.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/shippingInvoice/ShippingInvoiceFactory.java @@ -4,6 +4,7 @@ import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; import lombok.extern.slf4j.Slf4j; +import org.apache.catalina.User; import org.apache.commons.lang3.tuple.Pair; import org.jeecg.modules.business.controller.UserException; import org.jeecg.modules.business.domain.codeGeneration.CompleteInvoiceCodeRule; @@ -16,15 +17,20 @@ import org.jeecg.modules.business.vo.PromotionDetail; import org.jeecg.modules.business.vo.ShippingFeesEstimation; import org.jeecg.modules.business.vo.SkuQuantity; import org.jeecg.modules.business.vo.SkuWeightDiscountServiceFees; +import org.jeecg.modules.business.vo.clientPlatformOrder.section.OrdersStatisticData; import org.jetbrains.annotations.NotNull; import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; import org.springframework.dao.IncorrectResultSizeDataAccessException; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; +import javax.mail.MessagingException; import java.math.BigDecimal; import java.math.RoundingMode; import java.text.SimpleDateFormat; +import java.time.LocalDate; import java.util.*; import java.util.concurrent.TimeUnit; import java.util.function.Function; @@ -51,6 +57,8 @@ public class ShippingInvoiceFactory { private final SkuPromotionHistoryMapper skuPromotionHistoryMapper; private final ISavRefundService savRefundService; private final ISavRefundWithDetailService savRefundWithDetailService; + private final EmailService emailService; + private final Environment env; private final SimpleDateFormat SUBJECT_FORMAT = new SimpleDateFormat("yyyy-MM-dd"); @@ -78,7 +86,7 @@ public class ShippingInvoiceFactory { ExchangeRatesMapper exchangeRatesMapper, IPurchaseOrderService purchaseOrderService, PurchaseOrderContentMapper purchaseOrderContentMapper, SkuPromotionHistoryMapper skuPromotionHistoryMapper, ISavRefundService savRefundService, - ISavRefundWithDetailService savRefundWithDetailService) { + ISavRefundWithDetailService savRefundWithDetailService, EmailService emailService, Environment env) { this.platformOrderService = platformOrderService; this.clientMapper = clientMapper; this.shopMapper = shopMapper; @@ -93,6 +101,8 @@ public class ShippingInvoiceFactory { this.skuPromotionHistoryMapper = skuPromotionHistoryMapper; this.savRefundService = savRefundService; this.savRefundWithDetailService = savRefundWithDetailService; + this.emailService = emailService; + this.env = env; } /** @@ -160,7 +170,7 @@ public class ShippingInvoiceFactory { * channel price, this exception will be thrown. */ @Transactional - public CompleteInvoice createCompleteShippingInvoice(String username, String customerId, List orderIds, String shippingMethod, String start, String end) throws UserException { + public CompleteInvoice createCompleteShippingInvoice(String username, String customerId, BigDecimal balance, List orderIds, String shippingMethod, String start, String end) throws UserException, MessagingException { log.info("Creating a complete invoice for \n client ID: {}, order IDs: {}]", customerId, orderIds); // find orders and their contents of the invoice Map> uninvoicedOrderToContent = platformOrderService.fetchOrderData(orderIds); @@ -181,8 +191,9 @@ public class ShippingInvoiceFactory { else if(shippingMethod.equals("all")) subject = String.format("Purchase and Shipping fees, order time from %s to %s", start, end); else throw new UserException("Couldn't create complete invoice for unknown shipping method"); - - return createInvoice(username, customerId, shopIds, uninvoicedOrderToContent, savRefunds, subject); + if(balance != null) + return createCompleteInvoiceWithBalance(username, customerId, balance, shopIds, uninvoicedOrderToContent, savRefunds, subject); + return createInvoice(username, customerId, null, shopIds, uninvoicedOrderToContent, savRefunds, subject); } @@ -209,7 +220,7 @@ public class ShippingInvoiceFactory { * channel price, this exception will be thrown. */ @Transactional - public CompleteInvoice createInvoice(String username, String customerId, List shopIds, + public CompleteInvoice createInvoice(String username, String customerId, BigDecimal balance, List shopIds, Map> orderAndContent, List savRefunds, String subject) throws UserException { Client client = clientMapper.selectById(customerId); @@ -235,10 +246,145 @@ public class ShippingInvoiceFactory { shops.forEach(shop -> shopPackageMatFeeMap.put(shop.getId(), shop.getPackagingMaterialFee())); String invoiceCode = generateCompleteInvoiceCode(); log.info("New invoice code: {}", invoiceCode); - calculateFees(logisticChannelMap, orderAndContent, channelPriceMap, countryList, skuRealWeights, skuServiceFees, + calculateFees(balance, logisticChannelMap, orderAndContent, channelPriceMap, countryList, skuRealWeights, skuServiceFees, latestDeclaredValues, client, shopServiceFeeMap, shopPackageMatFeeMap, invoiceCode); BigDecimal eurToUsd = exchangeRatesMapper.getLatestExchangeRate("EUR", "USD"); + List orderIds = orderAndContent.keySet().stream().map(PlatformOrder::getId).collect(toList()); + List skuQuantities = platformOrderContentService.searchOrderContent(orderIds); + String purchaseID = purchaseOrderService.addPurchase(username, client, invoiceCode, skuQuantities, orderAndContent); + + List purchaseOrderSkuList = purchaseOrderContentMapper.selectInvoiceDataByID(purchaseID); + List promotionDetails = skuPromotionHistoryMapper.selectPromotionByPurchase(purchaseID); + if (savRefunds != null) { + updateSavRefundsInDb(savRefunds, invoiceCode); + } + + updateOrdersAndContentsInDb(orderAndContent); + + return new CompleteInvoice(client, invoiceCode, subject, orderAndContent, savRefunds, + purchaseOrderSkuList, promotionDetails, eurToUsd); + } + + /** + * Creates a complete invoice for a client, based of its balance, a list of shops, a date range. + *

    + * To generate an invoice, it + *

      + *
    1. Search orders and their contents based on shop and date range
    2. + *
    3. Generate a new invoice code
    4. + *
    5. Find proper logistic channel price for each order
    6. + *
    7. Update prices of orders and their contents
    8. + *
    9. Generate a invoice
    10. + *
    11. Update invoiced their orders and contents to DB
    12. + *
    + * + * @param username Current username + * @param customerId Customer ID + * @param balance Customer balance + * @param shopIds Shop IDs + * @param savRefunds List of SAV refunds + * @param subject Invoice subject + * @return the generated invoice + * @throws UserException if package used by the invoice can not or find more than 1 logistic + * channel price, this exception will be thrown. + */ + @Transactional + public CompleteInvoice createCompleteInvoiceWithBalance(String username, String customerId, BigDecimal balance, List shopIds, + Map> orderAndContent, + List savRefunds, String subject) throws UserException, MessagingException { + // sorting by order time + orderAndContent = orderAndContent.entrySet().stream().sorted( + Map.Entry.comparingByKey(Comparator.comparing(PlatformOrder::getOrderTime)) + ).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (oldValue, newValue) -> oldValue, LinkedHashMap::new)); + + Client client = clientMapper.selectById(customerId); + BigDecimal virtualBalance = balance; + Map> ordersToRemove = new HashMap<>(); + log.info("User {} is creating a complete invoice in {} order, for customer {}", username, client.getInternalCode(), client.getIsChronologicalOrder().equals("0") ? "first can invoice" : "chronological"); + + if (orderAndContent == null || orderAndContent.isEmpty()) { + throw new UserException("No platform order in the selected period!"); + } + log.info("Orders to be invoiced: {}", orderAndContent); + Map skuRealWeights = new HashMap<>(); + Map skuServiceFees = new HashMap<>(); + skuDataPreparation(skuRealWeights, skuServiceFees); + List countryList = countryService.findAll(); + Map logisticChannelMap = logisticChannelMapper.getAll().stream() + .collect(toMap(LogisticChannel::getId, Function.identity())); + Map> channelPriceMap = getChannelPriceMap(logisticChannelMap, orderAndContent, true); + List latestDeclaredValues = skuDeclaredValueService.getLatestDeclaredValues(); + + List shops = shopMapper.selectBatchIds(shopIds); + Map shopServiceFeeMap = new HashMap<>(); + Map shopPackageMatFeeMap = new HashMap<>(); + shops.forEach(shop -> shopServiceFeeMap.put(shop.getId(), shop.getOrderServiceFee())); + shops.forEach(shop -> shopPackageMatFeeMap.put(shop.getId(), shop.getPackagingMaterialFee())); + String invoiceCode = generateCompleteInvoiceCode(); + + log.info("New invoice code: {}", invoiceCode); + + boolean skip = false;// isChronologicalOrder = 1 && insufficient balance => skip = true + for(Map.Entry> entry : orderAndContent.entrySet()) { + if(skip) { + if(ordersToRemove.containsKey("skip")) + ordersToRemove.get("skip").add(entry.getKey().getPlatformOrderId()); + else + ordersToRemove.put("skip", Collections.singletonList(entry.getKey().getPlatformOrderId())); + continue; + } + BigDecimal estimatedVirtualBalance; + try { + estimatedVirtualBalance = calculateFeeForOrder(username, virtualBalance, logisticChannelMap, entry.getKey(), entry.getValue(), channelPriceMap, countryList, skuRealWeights, skuServiceFees, + latestDeclaredValues, client, shopServiceFeeMap, shopPackageMatFeeMap, invoiceCode); + } catch (UserException e) { + log.error("Couldn't calculate fee for order {} !", entry.getKey().getId()); + if(ordersToRemove.containsKey("error")) + ordersToRemove.get("error").add(entry.getKey().getPlatformOrderId()); + else + ordersToRemove.put("error", Collections.singletonList(entry.getKey().getPlatformOrderId())); + continue; + } + if(estimatedVirtualBalance.compareTo(BigDecimal.ZERO) < 0) { + log.error("Not enough balance for order {} !", entry.getKey().getId()); + if(ordersToRemove.containsKey("balance")) + ordersToRemove.get("balance").add(entry.getKey().getPlatformOrderId()); + else + ordersToRemove.put("balance", Collections.singletonList(entry.getKey().getPlatformOrderId())); + if(client.getIsChronologicalOrder().equals("1")) + skip = true; + continue; + } + virtualBalance = estimatedVirtualBalance; + } + if(!ordersToRemove.isEmpty() && ordersToRemove.get("balance") != null) { + String emailSubject = "[" + LocalDate.now() + "] Rapport de facturation automatique WIA App"; + String destEmail = env.getProperty("spring.mail.username"); + String templateName = "client/confirmedClientsInvoicingJobReport.ftl"; + Map templateModel = new HashMap<>(); + templateModel.put("errors", ordersToRemove.get("balance")); +// templateModel.put("skipped", ordersToRemove.get("skip")); + templateModel.put("client", client); + templateModel.put("chronologicalOrder", client.getIsChronologicalOrder()); + emailService.newSendSimpleMessage(destEmail, emailSubject, templateName, templateModel); + } + // removing orders that can't be invoiced + System.out.println("Orders and content size BEFORE : " + orderAndContent.size()); + System.out.println("Orders to remove size : " + ordersToRemove.size()); + for(Map.Entry> entry : ordersToRemove.entrySet()) { + for(String platformOrderId : entry.getValue()) { + orderAndContent.keySet().removeIf(order -> order.getPlatformOrderId().equals(platformOrderId)); + } + } + System.out.println("Orders and content size AFTER : " + orderAndContent.size()); + + BigDecimal eurToUsd = exchangeRatesMapper.getLatestExchangeRate("EUR", "USD"); + if(orderAndContent.isEmpty()) { + log.error("No order was invoiced for customer {}, : Please check if the orders are in the correct erp status and if the customer has enough balance.", client.getInternalCode()); + throw new UserException("No order was invoiced for customer " + client.getInternalCode() + + " : Please check if the orders are in the correct erp status and if the customer has enough balance."); + } List orderIds = orderAndContent.keySet().stream().map(PlatformOrder::getId).collect(toList()); List skuQuantities = platformOrderContentService.searchOrderContent(orderIds); @@ -328,7 +474,7 @@ public class ShippingInvoiceFactory { * channel price, this exception will be thrown. */ @Transactional - public ShippingInvoice createInvoice(String customerId, List shopIds, Date begin, Date end, List erpStatuses, List warehouses) throws UserException { + public ShippingInvoice createInvoice(String customerId, List shopIds, Date begin, Date end, List erpStatuses, List warehouses, BigDecimal balance) throws UserException { log.info( "Creating an invoice with arguments:\n client ID: {}, shop IDs: {}, period:[{} - {}]", customerId, shopIds.toString(), begin, end @@ -345,7 +491,7 @@ public class ShippingInvoiceFactory { ); uninvoicedOrderToContent = platformOrderService.findUninvoicedOrders(shopIds, begin, end, warehouses); } - else if (erpStatuses.toString().equals("[1, 2]")) { + else if (erpStatuses.toString().equals("[1, 2]") || erpStatuses.toString().equals("[1]")) { subject = String.format( "Pre-Shipping fees order time from %s to %s", SUBJECT_FORMAT.format(begin), @@ -361,6 +507,9 @@ public class ShippingInvoiceFactory { ); uninvoicedOrderToContent = platformOrderService.findUninvoicedOrderContentsForShopsAndStatus(shopIds, begin, end, erpStatuses, warehouses); } + if(balance != null) { + return createInvoiceWithBalance(customerId, balance, shopIds, uninvoicedOrderToContent, savRefunds, subject, false); + } return createInvoice(customerId, shopIds, uninvoicedOrderToContent, savRefunds, subject, false); } @@ -419,7 +568,7 @@ public class ShippingInvoiceFactory { shops.forEach(shop -> shopPackageMatFeeMap.put(shop.getId(), shop.getPackagingMaterialFee())); String invoiceCode = generateInvoiceCode(); log.info("New invoice code: {}", invoiceCode); - calculateFees(logisticChannelMap, orderAndContent, channelPriceMap, countryList, skuRealWeights, skuServiceFees, + calculateFees(null, logisticChannelMap, orderAndContent, channelPriceMap, countryList, skuRealWeights, skuServiceFees, latestDeclaredValues, client, shopServiceFeeMap, shopPackageMatFeeMap, invoiceCode); BigDecimal eurToUsd = exchangeRatesMapper.getLatestExchangeRate("EUR", "USD"); if (savRefunds != null) { @@ -429,6 +578,80 @@ public class ShippingInvoiceFactory { updateOrdersAndContentsInDb(orderAndContent); return invoice; } + /** + * Creates an invoice based for a client, it's balance, a list of shops, a date range. + *

    + * To generate an invoice, it + *

      + *
    1. Search orders and their contents based on shop and date range
    2. + *
    3. Generate a new invoice code
    4. + *
    5. Find propre logistic channel price for each order
    6. + *
    7. Update prices of orders and their contents
    8. + *
    9. Generate a invoice
    10. + *
    11. Update invoiced their orders and contents to DB
    12. + *
    + * + * @param customerId Customer ID + * @param balance Balance + * @param shopIds Shop IDs + * @param subject Invoice subject + * @param orderAndContent Map between PlatformOrder and their contents + * @param savRefunds List of SAV refunds + * @param skipShippingTimeComparing Skip comparing shipping time, true for Pre-shipping, false otherwise + * @return the generated invoice + * @throws UserException if package used by the invoice can not or find more than 1 logistic + * channel price, this exception will be thrown. + */ + @Transactional + public ShippingInvoice createInvoiceWithBalance(String customerId, BigDecimal balance, List shopIds, + Map> orderAndContent, + List savRefunds, + String subject, boolean skipShippingTimeComparing) throws UserException { + log.info("Orders to be invoiced: {}", orderAndContent); + if (orderAndContent == null || orderAndContent.isEmpty()) { + throw new UserException("No platform order in the selected period!"); + } + // TODO : check why invoicing total changes everytime + Map skuRealWeights = new HashMap<>(); + Map skuServiceFees = new HashMap<>(); + skuDataPreparation(skuRealWeights, skuServiceFees); + List countryList = countryService.findAll(); + Map> channelPriceMap; + Map logisticChannelMap = logisticChannelMapper.getAll().stream() + .collect(toMap(LogisticChannel::getId, Function.identity())); + if(subject.contains("order time")) { + channelPriceMap = getChannelPriceMap(logisticChannelMap, orderAndContent, skipShippingTimeComparing, "order"); + } + else { + channelPriceMap = getChannelPriceMap(logisticChannelMap, orderAndContent, skipShippingTimeComparing); + } + List latestDeclaredValues = skuDeclaredValueService.getLatestDeclaredValues(); + + Client client = clientMapper.selectById(customerId); + List shops = shopMapper.selectBatchIds(shopIds); + Map shopServiceFeeMap = new HashMap<>(); + Map shopPackageMatFeeMap = new HashMap<>(); + shops.forEach(shop -> shopServiceFeeMap.put(shop.getId(), shop.getOrderServiceFee())); + shops.forEach(shop -> shopPackageMatFeeMap.put(shop.getId(), shop.getPackagingMaterialFee())); + String invoiceCode = generateInvoiceCode(); + log.info("New invoice code: {}", invoiceCode); + System.out.println("Order and content size BEFORE : " + orderAndContent.size()); + Map> ordersWithPB = calculateFees(balance, logisticChannelMap, orderAndContent, channelPriceMap, countryList, skuRealWeights, skuServiceFees, + latestDeclaredValues, client, shopServiceFeeMap, shopPackageMatFeeMap, invoiceCode); + orderAndContent.entrySet().removeIf(entries -> ordersWithPB.containsKey(entries.getKey().getId())); + System.out.println("Order and content size AFTER : " + orderAndContent.size()); + if(orderAndContent.isEmpty()) { + log.error("No order was invoiced for customer {} because : {}", client.getInternalCode(), ordersWithPB); + throw new UserException("Customer " + customerId + " errors : " + ordersWithPB); + } + BigDecimal eurToUsd = exchangeRatesMapper.getLatestExchangeRate("EUR", "USD"); + if (savRefunds != null) { + updateSavRefundsInDb(savRefunds, invoiceCode); + } + ShippingInvoice invoice = new ShippingInvoice(client, invoiceCode, subject, orderAndContent, savRefunds, eurToUsd); + updateOrdersAndContentsInDb(orderAndContent); + return invoice; + } /** * Construct a map between LogisticChannel and LogisticChannelPrices, by using distinct country names and @@ -484,7 +707,7 @@ public class ShippingInvoiceFactory { } } - private Map> calculateFees(Map logisticChannelMap, Map> orderAndContent, + private Map> calculateFees(BigDecimal balance, Map logisticChannelMap, Map> orderAndContent, Map> channelPriceMap, List countryList, Map skuRealWeights, @@ -496,30 +719,45 @@ public class ShippingInvoiceFactory { String invoiceCode ) throws UserException { Map> platformOrderIdsWithPb = new HashMap<>(); + // Virtual balance is only used for client type 1 in invoicing job + BigDecimal virtualBalance = balance; + List insufficientBalanceOrders = new ArrayList<>(); + boolean skip = false; + Map> orderContentMap = new HashMap<>(orderAndContent); + orderContentMap = orderContentMap.entrySet().stream().sorted( + Map.Entry.comparingByKey(Comparator.comparing(PlatformOrder::getOrderTime)) + ).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (oldValue, newValue) -> oldValue, LinkedHashMap::new)); // find logistic channel price for each order based on its content - for (PlatformOrder uninvoicedOrder : orderAndContent.keySet()) { - List contents = orderAndContent.get(uninvoicedOrder); + for (PlatformOrder uninvoicedOrder : orderContentMap.keySet()) { + if(skip) { + if(client.getInternalCode().equals("FT")) { + System.out.println("uninvoicedOrder order time : " + uninvoicedOrder.getOrderTime()); + } + platformOrderIdsWithPb.put(uninvoicedOrder.getId(), Collections.singletonList("Skipped")); + continue; + } + List contents = orderContentMap.get(uninvoicedOrder); if (contents.isEmpty()) { - throw new UserException("Order: {} doesn't have content", uninvoicedOrder.getPlatformOrderId()); + throw new UserException("Order: {} doesn't have content", uninvoicedOrder.getId()); } log.info("Calculating price for {} of order {}", contents, uninvoicedOrder); - Map contentMap = new HashMap<>(); + Map contentSkuQtyMap = new HashMap<>(); for (PlatformOrderContent content : contents) { String skuId = content.getSkuId(); - if (contentMap.containsKey(skuId)) { - contentMap.put(skuId, contentMap.get(skuId) + content.getQuantity()); + if (contentSkuQtyMap.containsKey(skuId)) { + contentSkuQtyMap.put(skuId, contentSkuQtyMap.get(skuId) + content.getQuantity()); } else { - contentMap.put(skuId, content.getQuantity()); + contentSkuQtyMap.put(skuId, content.getQuantity()); } } // calculate weight of an order Pair> contentWeightResult = platformOrderContentService.calculateWeight( - contentMap, + contentSkuQtyMap, skuRealWeights ); if(!contentWeightResult.getValue().isEmpty()) { - platformOrderIdsWithPb.put(uninvoicedOrder.getPlatformOrderId(), contentWeightResult.getValue()); + platformOrderIdsWithPb.put(uninvoicedOrder.getId(), contentWeightResult.getValue()); continue; } BigDecimal contentWeight = contentWeightResult.getKey(); @@ -528,20 +766,16 @@ public class ShippingInvoiceFactory { logisticChannelPair = findAppropriatePrice(countryList, logisticChannelMap, channelPriceMap, uninvoicedOrder, contentWeight); } - catch (UserException e) { - platformOrderIdsWithPb.put(uninvoicedOrder.getPlatformOrderId(), Collections.singletonList(e.getMessage())); + catch (RuntimeException | UserException e) { + platformOrderIdsWithPb.put(uninvoicedOrder.getId(), Collections.singletonList(e.getMessage())); continue; } LogisticChannelPrice price = logisticChannelPair.getRight(); - // update attributes of orders and theirs content + BigDecimal packageMatFee = shopPackageMatFeeMap.get(uninvoicedOrder.getShopId()); - if(packageMatFee.compareTo(BigDecimal.ZERO) > 0 && logisticChannelPair.getLeft().getWarehouseInChina().equalsIgnoreCase("0")) { - uninvoicedOrder.setPackagingMaterialFee(packageMatFee); - } - uninvoicedOrder.setFretFee(price.getRegistrationFee()); - uninvoicedOrder.setPickingFee(price.getAdditionalCost()); - uninvoicedOrder.setOrderServiceFee(shopServiceFeeMap.get(uninvoicedOrder.getShopId())); - uninvoicedOrder.setShippingInvoiceNumber(invoiceCode); + BigDecimal fretFee = price.getRegistrationFee(); + BigDecimal pickingFee = price.getAdditionalCost(); + BigDecimal orderServiceFee = shopServiceFeeMap.get(uninvoicedOrder.getShopId()); BigDecimal totalShippingFee = price.calculateShippingPrice(contentWeight); BigDecimal pickingFeePerItem = price.getPickingFeePerItem(); BigDecimal clientVatPercentage = client.getVatPercentage(); @@ -560,6 +794,32 @@ public class ShippingInvoiceFactory { if (vatApplicable && minimumDeclaredValue != null) { totalVAT = calculateTotalVat(totalDeclaredValue, clientVatPercentage, minimumDeclaredValue); } + if(virtualBalance != null){ + virtualBalance = virtualBalance + .subtract(packageMatFee) + .subtract(fretFee) + .subtract(pickingFee) + .subtract(orderServiceFee) + .subtract(totalShippingFee) + .subtract(totalVAT); + if (virtualBalance.compareTo(BigDecimal.ZERO) < 0) { + if(client.getIsChronologicalOrder().equals("1")) { + skip = true; + } + insufficientBalanceOrders.add(uninvoicedOrder); + platformOrderIdsWithPb.put(uninvoicedOrder.getId(), Collections.singletonList("Insufficient balance, order was not invoiced.")); + continue; + } + } + + // update attributes of orders and theirs content + if(packageMatFee.compareTo(BigDecimal.ZERO) > 0 && logisticChannelPair.getLeft().getWarehouseInChina().equalsIgnoreCase("0")) { + uninvoicedOrder.setPackagingMaterialFee(packageMatFee); + } + uninvoicedOrder.setFretFee(fretFee); + uninvoicedOrder.setPickingFee(pickingFee); + uninvoicedOrder.setOrderServiceFee(orderServiceFee); + uninvoicedOrder.setShippingInvoiceNumber(invoiceCode); // Since we always round up when distributing shipping fees to contents, sometimes the final total sum // is bigger than initial total shipping fee, the remedy is to deduct from the initial total, so we never go // above it @@ -570,9 +830,167 @@ public class ShippingInvoiceFactory { vatApplicable, pickingFeePerItem, content, remainingShippingFee); } } + if(!insufficientBalanceOrders.isEmpty()) { + //send mail + String emailSubject = "[" + LocalDate.now() + "] Rapport de facturation automatique WIA App"; + String destEmail = env.getProperty("spring.mail.username"); + String templateName = "client/confirmedClientsInvoicingJobReport.ftl"; + Map templateModel = new HashMap<>(); + templateModel.put("errors", insufficientBalanceOrders); + templateModel.put("client", client); + templateModel.put("chronologicalOrder", client.getIsChronologicalOrder()); + try { + emailService.newSendSimpleMessage(destEmail, emailSubject, templateName, templateModel); + } catch (MessagingException e) { + throw new RuntimeException(e); + } + } + // removing orders that can't be invoiced + log.info("Number of orders with problem for client {} : {}", client.getInternalCode(), platformOrderIdsWithPb.size()); + platformOrderIdsWithPb.keySet().forEach(System.out::println); return platformOrderIdsWithPb; } + /** + * Calculates shipping fees of an order, updates order and contents + * and returns the estimated virtual balance + * if invoice is complete invoice, we make sure we have enough balance + * @param username + * @param balance virtual balance + * @param logisticChannelMap + * @param order + * @param contents + * @param channelPriceMap + * @param countryList + * @param skuRealWeights + * @param skuServiceFees + * @param latestDeclaredValues + * @param client + * @param shopServiceFeeMap + * @param shopPackageMatFeeMap + * @param invoiceCode + * @return + * @throws UserException + */ + private BigDecimal calculateFeeForOrder(String username, + BigDecimal balance, + Map logisticChannelMap, + PlatformOrder order, + List contents, + Map> channelPriceMap, + List countryList, + Map skuRealWeights, + Map skuServiceFees, + List latestDeclaredValues, + Client client, + Map shopServiceFeeMap, + Map shopPackageMatFeeMap, + String invoiceCode + ) throws UserException { + // Virtual balance is only used for client type 1 in invoicing job + BigDecimal virtualBalance = balance; + // find logistic channel price for each order based on its content + if (contents.isEmpty()) { + throw new UserException("Order: {} doesn't have content", order.getPlatformOrderId()); + } + log.info("Calculating price for {} of order {}", contents, order); + Map contentSkuQtyMap = new HashMap<>(); + for (PlatformOrderContent content : contents) { + String skuId = content.getSkuId(); + if (contentSkuQtyMap.containsKey(skuId)) { + contentSkuQtyMap.put(skuId, contentSkuQtyMap.get(skuId) + content.getQuantity()); + } else { + contentSkuQtyMap.put(skuId, content.getQuantity()); + } + } + + // calculate weight of an order + Pair> contentWeightResult = platformOrderContentService.calculateWeight( + contentSkuQtyMap, + skuRealWeights + ); + if(!contentWeightResult.getValue().isEmpty()) { + return null; + } + BigDecimal contentWeight = contentWeightResult.getKey(); + Pair logisticChannelPair; + try { + logisticChannelPair = findAppropriatePrice(countryList, logisticChannelMap, + channelPriceMap, order, contentWeight); + } + catch (UserException e) { + log.error(e.getMessage()); + return null; + } + LogisticChannelPrice price = logisticChannelPair.getRight(); + + BigDecimal packageMatFee = shopPackageMatFeeMap.get(order.getShopId()); + BigDecimal fretFee = price.getRegistrationFee(); + BigDecimal pickingFee = price.getAdditionalCost(); + BigDecimal orderServiceFee = shopServiceFeeMap.get(order.getShopId()); + BigDecimal totalShippingFee = price.calculateShippingPrice(contentWeight); + BigDecimal pickingFeePerItem = price.getPickingFeePerItem(); + BigDecimal clientVatPercentage = client.getVatPercentage(); + Map contentDeclaredValueMap = new HashMap<>(); + BigDecimal totalDeclaredValue = calculateTotalDeclaredValue(contents, contentDeclaredValueMap, latestDeclaredValues); + BigDecimal totalVAT = BigDecimal.ZERO; + boolean vatApplicable = clientVatPercentage.compareTo(BigDecimal.ZERO) > 0 + && EU_COUNTRY_LIST.contains(order.getCountry()) + // If picking fee per item = 0, it means the package was sent from China so VAT applicable + && price.getPickingFeePerItem().compareTo(BigDecimal.ZERO) == 0; + // In case where VAT is applicable, and the transport line has a minimum declared value (MDV) per PACKAGE + // We need to first calculate the total declared value and compare it to the MDV + // If the total declared value is below the MDV, then the VAT should be calculated with the MDV and + // then proportionally applied to each content + BigDecimal minimumDeclaredValue = price.getMinimumDeclaredValue(); + if (vatApplicable && minimumDeclaredValue != null) { + totalVAT = calculateTotalVat(totalDeclaredValue, clientVatPercentage, minimumDeclaredValue); + } + if(virtualBalance != null){ + virtualBalance = virtualBalance + .subtract(packageMatFee) + .subtract(fretFee) + .subtract(pickingFee) + .subtract(orderServiceFee) + .subtract(totalShippingFee) + .subtract(totalVAT); + if (virtualBalance.compareTo(BigDecimal.ZERO) < 0) { + return virtualBalance; + } + // if we are dealing with complete invoice, before inserting orders info + // we calcute purchase fee and make sure we have enough balance + if(invoiceCode.toCharArray()[8] == '7') { + BigDecimal eurToUsd = exchangeRatesMapper.getLatestExchangeRate("EUR", "USD"); + List skuQuantities = platformOrderContentService.searchOrderContent(Collections.singletonList(order.getId())); + List details = platformOrderService.searchPurchaseOrderDetail(skuQuantities); + OrdersStatisticData data = OrdersStatisticData.makeData(details, null); + BigDecimal purchaseFee = data.finalAmount(); + virtualBalance = virtualBalance.subtract(purchaseFee.multiply(eurToUsd)); + } + if (virtualBalance.compareTo(BigDecimal.ZERO) < 0) { + return virtualBalance; + } + } + // update attributes of orders and theirs content + if(packageMatFee.compareTo(BigDecimal.ZERO) > 0 && logisticChannelPair.getLeft().getWarehouseInChina().equalsIgnoreCase("0")) { + order.setPackagingMaterialFee(packageMatFee); + } + order.setFretFee(fretFee); + order.setPickingFee(pickingFee); + order.setOrderServiceFee(orderServiceFee); + order.setShippingInvoiceNumber(invoiceCode); + // Since we always round up when distributing shipping fees to contents, sometimes the final total sum + // is bigger than initial total shipping fee, the remedy is to deduct from the initial total, so we never go + // above it + BigDecimal remainingShippingFee = totalShippingFee; + for (PlatformOrderContent content : contents) { + remainingShippingFee = calculateAndUpdateContentFees(skuRealWeights, skuServiceFees, order, contentWeight, + totalShippingFee, clientVatPercentage, contentDeclaredValueMap, totalDeclaredValue, totalVAT, + vatApplicable, pickingFeePerItem, content, remainingShippingFee); + } + return virtualBalance; + } + private void updateOrdersAndContentsInDb(Map> orderAndContent) { // update them to DB after invoiced platformOrderService.updateBatchById(orderAndContent.keySet()); @@ -801,7 +1219,7 @@ public class ShippingInvoiceFactory { shopPackageMatFeeMap.put(shop.getId(), shop.getPackagingMaterialFee()); Map> orders = uninvoicedOrdersByShopId.get(shop.getId()); try { - Map> orderIdErrorMap = calculateFees(logisticChannelMap, orders, channelPriceMap, countryList, skuRealWeights, skuServiceFees, + Map> orderIdErrorMap = calculateFees(null, logisticChannelMap, orders, channelPriceMap, countryList, skuRealWeights, skuServiceFees, latestDeclaredValues, client, shopServiceFeeMap,shopPackageMatFeeMap, null); if(!orderIdErrorMap.isEmpty()) { Map.Entry> errorEntry = orderIdErrorMap.entrySet().iterator().next(); @@ -858,7 +1276,6 @@ public class ShippingInvoiceFactory { .collect(toMap(LogisticChannel::getId, Function.identity())); Map> channelPriceMap = getChannelPriceMap(logisticChannelMap, ordersMap, true); - for (Shop shop : shops) { Map shopServiceFeeMap = new HashMap<>(); Map shopPackageMatFeeMap = new HashMap<>(); @@ -866,24 +1283,10 @@ public class ShippingInvoiceFactory { shopPackageMatFeeMap.put(shop.getId(), shop.getPackagingMaterialFee()); Map> orders = uninvoicedOrdersByShopId.get(shop.getId()); try { - Map> ordersCopy = new HashMap<>(orders); - Map> platformOrderIdErrorMap = calculateFees(logisticChannelMap, orders, channelPriceMap, countryList, skuRealWeights, skuServiceFees, + Map> platformOrderIdErrorMap = calculateFees(null, logisticChannelMap, orders, channelPriceMap, countryList, skuRealWeights, skuServiceFees, latestDeclaredValues, client, shopServiceFeeMap, shopPackageMatFeeMap, null); - System.out.println("Error List : " + platformOrderIdErrorMap); - for(Map.Entry> entry : orders.entrySet()) { - for(Map.Entry> errorEntry: platformOrderIdErrorMap.entrySet()) { - if(entry.getKey().getPlatformOrderId().equals(errorEntry.getKey())) { - errorMessages.addAll(errorEntry.getValue()); - System.out.println("Error List size before : " + platformOrderIdErrorMap.size()); - System.out.println("Platform Order Id to remove : " + errorEntry.getKey()); - ordersCopy.remove(entry.getKey()); - platformOrderIdErrorMap.remove(errorEntry.getKey()); - System.out.println("Error List size after : " + platformOrderIdErrorMap.size()); - break; - } - } - } - orders = ordersCopy; + platformOrderIdErrorMap.forEach((key, value) -> errorMessages.addAll(value)); + orders.entrySet().removeIf(entries -> platformOrderIdErrorMap.containsKey(entries.getKey().getId())); List estimationsOrderIds = orders.keySet().stream().map(PlatformOrder::getId).collect(Collectors.toList()); BigDecimal eurToUsd = exchangeRatesMapper.getLatestExchangeRate("EUR", "USD"); ShippingInvoice invoice = new ShippingInvoice(client, "", "", orders, null, eurToUsd); diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/entity/Client.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/entity/Client.java index c98e66c02..f4826d165 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/entity/Client.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/entity/Client.java @@ -155,12 +155,6 @@ public class Client implements Serializable { @Excel(name = "公司识别码数值", width = 15) @ApiModelProperty(value = "公司识别码数值") private String companyIdValue; - /** - * 账户余额 - */ - @Excel(name = "账户余额", width = 15) - @ApiModelProperty(value = "账户余额") - private BigDecimal balance; /** * IOSS号码 */ @@ -180,10 +174,32 @@ public class Client implements Serializable { @Dict(dicCode = "yn") @ApiModelProperty(value = "是否活跃") private String active; + /** + * 物流发票是否包含采购 + * */ + @Excel(name = "物流发票是否包含采购", width = 15) + @ApiModelProperty(value = "物流发票是否包含采购") + private java.lang.String isCompleteInvoice; + /** + * category id + * */ + @Excel(name = "category id", width = 15, dictTable = "client_category", dicText = "name", dicCode = "id") + @Dict(dictTable = "client_category", dicText = "name", dicCode = "id") + @ApiModelProperty(value = "category id") + private java.lang.String clientCategoryId; + /** + * balance threshold before alert + * */ + @Excel(name = "balance threshold before alert", width = 15) + @ApiModelProperty(value = "balance threshold before alert") + private java.math.BigDecimal balanceThreshold; + /** + * invoice in chronological order or first can invoice + * */ + @Excel(name = "invoice in chronological order or first can invoice", width = 15) + @ApiModelProperty(value = "invoice in chronological order or first can invoice") + private java.lang.String isChronologicalOrder; - @Excel(name = "是否完整发票", width = 15) - @ApiModelProperty(value = "完整发票") - private String isCompleteInvoice; public String fullName() { return firstName + " " + surname; } diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/entity/ClientCategory.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/entity/ClientCategory.java index 766963988..365b2ae19 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/entity/ClientCategory.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/entity/ClientCategory.java @@ -60,4 +60,8 @@ public class ClientCategory implements Serializable { @Excel(name = "description", width = 15) @ApiModelProperty(value = "description") private java.lang.String description; + /**balance threshold before alert*/ + @Excel(name = "balance threshold before alert", width = 15) + @ApiModelProperty(value = "balance threshold before alert") + private java.math.BigDecimal balanceThreshold; } diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/entity/OrderContentDetail.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/entity/OrderContentDetail.java index 783a70c40..387e26474 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/entity/OrderContentDetail.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/entity/OrderContentDetail.java @@ -38,6 +38,9 @@ public class OrderContentDetail { */ public BigDecimal totalPrice() { BigDecimal unit = skuDetail.getPrice().getPrice(quantity, exchangeRate); + if(unit == null) { + System.out.println("Unit is null : " + skuDetail.getSkuId() + "sku price: " + skuDetail.getPrice() + "quantity: " + quantity); + } BigDecimal total = unit.multiply(new BigDecimal(quantity)); log.info("unit: {}", unit); log.info("total: {}", total); diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/entity/SkuPrice.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/entity/SkuPrice.java index 9226c4e1f..a9a599c3e 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/entity/SkuPrice.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/entity/SkuPrice.java @@ -121,7 +121,7 @@ public class SkuPrice implements Serializable { priceCandidate = priceRmb.divide(eurToRmb, RoundingMode.HALF_UP); discountedPriceCandidate = discountedPriceRmb == null ? priceCandidate : discountedPriceRmb.divide(eurToRmb, RoundingMode.HALF_UP); } - if (quantity >= threshold) { + if (threshold != null && quantity >= threshold) { return discountedPriceCandidate; } return priceCandidate; diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/ClientCategoryMapper.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/ClientCategoryMapper.java index 9c9781c0b..da2809ee4 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/ClientCategoryMapper.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/ClientCategoryMapper.java @@ -1,10 +1,12 @@ package org.jeecg.modules.business.mapper; +import java.math.BigDecimal; import java.util.List; import org.apache.ibatis.annotations.Param; import org.jeecg.modules.business.entity.ClientCategory; import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.springframework.stereotype.Repository; /** * @Description: client category @@ -12,6 +14,7 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper; * @Date: 2023-10-19 * @Version: V1.0 */ +@Repository public interface ClientCategoryMapper extends BaseMapper { - + BigDecimal getBalanceThresholdByCategoryId(@Param("id") String id); } diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/ClientMapper.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/ClientMapper.java index 4450611f8..a54760dd0 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/ClientMapper.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/ClientMapper.java @@ -19,7 +19,7 @@ public interface ClientMapper extends BaseMapper { String getClientEntity(@Param("id") String id); Map getClientsEntity(@Param("ids") List ids); - String getClientByInternalCode(@Param("code") String code); - + String getClientIdByCode(@Param("code") String code); List getClientByType(@Param("type") String type); + Client getClientByCode(@Param("code") String internalCode); } diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/PlatformOrderContentMapper.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/PlatformOrderContentMapper.java index 76a5657a5..4cd603ffe 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/PlatformOrderContentMapper.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/PlatformOrderContentMapper.java @@ -81,4 +81,5 @@ public interface PlatformOrderContentMapper extends BaseMapper searchSkuPrice(@Param("skuIds") List skuIds); void fetchHighestPriorityAttribute(PlatformOrderContent content); + } diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/PlatformOrderMapper.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/PlatformOrderMapper.java index 244e85dfa..9e2ca8400 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/PlatformOrderMapper.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/PlatformOrderMapper.java @@ -176,7 +176,7 @@ public interface PlatformOrderMapper extends BaseMapper { @Param("shops") List shops, @Param("warehouses") List warehouses); - List fetchUninvoicedShippedOrderIDInShopsAndOrderTime(@Param("startDate") String startDate, + List fetchUninvoicedOrderIDInShopsAndOrderTime(@Param("startDate") String startDate, @Param("endDate") String endDate, @Param("shops") List shops, @Param("erpStatuses") List erpStatuses, @@ -192,4 +192,6 @@ public interface PlatformOrderMapper extends BaseMapper { List fetchEmptyLogisticChannelOrders(@Param("startDate") String startDate,@Param("endDate") String endDate); + void updateErpStatusByCode(@Param("invoiceCode") String invoiceCode, @Param("erpStatus") int erpStatus); + } diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/PurchaseOrderMapper.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/PurchaseOrderMapper.java index cf598d9c5..4389a4e99 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/PurchaseOrderMapper.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/PurchaseOrderMapper.java @@ -91,4 +91,9 @@ public interface PurchaseOrderMapper extends BaseMapper { String getInvoiceNumber(@Param("purchaseID") String purchaseID); + BigDecimal getPurchaseFeesByInvoiceCode(@Param("invoiceCode") String invoiceCode); + + void deleteInvoice(@Param("invoiceNumber") String invoiceNumber); + + void deleteBatchInvoice(@Param("invoiceNumbers") List invoiceNumbers); } diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/ShippingInvoiceMapper.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/ShippingInvoiceMapper.java index 5b050ddfc..7a28be419 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/ShippingInvoiceMapper.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/ShippingInvoiceMapper.java @@ -2,10 +2,7 @@ package org.jeecg.modules.business.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import org.apache.ibatis.annotations.Param; -import org.jeecg.modules.business.entity.Client; -import org.jeecg.modules.business.entity.PlatformOrder; -import org.jeecg.modules.business.entity.PlatformOrderContent; -import org.jeecg.modules.business.entity.ShippingInvoice; +import org.jeecg.modules.business.entity.*; import org.springframework.stereotype.Repository; import java.util.List; @@ -23,4 +20,5 @@ public interface ShippingInvoiceMapper extends BaseMapper { List fetchPlatformOrder(@Param("invoiceNumber") String invoiceNumber); List fetchPlatformOrderContent(@Param("platformOrderId") String platformOrderId); Client fetchShopOwnerFromInvoiceNumber(@Param("invoiceNumber") String invoiceNumber); + Currency fetchInvoiceCurrencyByCode(@Param("invoiceNumber") String invoiceCode); } diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/xml/ClientCategoryMapper.xml b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/xml/ClientCategoryMapper.xml index 02b894b6e..a6e52c67d 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/xml/ClientCategoryMapper.xml +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/xml/ClientCategoryMapper.xml @@ -1,5 +1,9 @@ - - + + \ No newline at end of file diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/xml/ClientMapper.xml b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/xml/ClientMapper.xml index 068aaab03..a0a5b92a1 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/xml/ClientMapper.xml +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/xml/ClientMapper.xml @@ -14,10 +14,15 @@ #{id} ; - SELECT id FROM client WHERE internal_code = #{code} + + - SELECT po.id FROM platform_order po JOIN logistic_channel lc ON po.logistic_channel_name = lc.zh_name @@ -643,15 +651,17 @@ - UPDATE platform_order + UPDATE platform_order po + JOIN shipping_invoice si ON po.shipping_invoice_number = si.invoice_number SET fret_fee = NULL, order_service_fee = NULL, shipping_invoice_number = NULL, picking_fee = 0.0, packaging_material_fee = 0.0, erp_status = - CASE erp_status - WHEN '4' THEN '3' + CASE + WHEN erp_status = '4' THEN '3' + WHEN erp_status = '2' AND si.create_by = 'system' THEN '1' ELSE erp_status END WHERE shipping_invoice_number = #{invoiceNumber}; diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/xml/PurchaseOrderMapper.xml b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/xml/PurchaseOrderMapper.xml index ecfb9302e..4b25f838e 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/xml/PurchaseOrderMapper.xml +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/xml/PurchaseOrderMapper.xml @@ -63,4 +63,22 @@ FROM purchase_order WHERE id = #{purchaseID} + + + DELETE + FROM purchase_order + WHERE invoice_number = #{invoiceNumber} + + + DELETE + FROM purchase_order + WHERE invoice_number IN + + #{invoiceNumber} + + diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/xml/ShippingInvoiceMapper.xml b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/xml/ShippingInvoiceMapper.xml index 8368613d1..076075165 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/xml/ShippingInvoiceMapper.xml +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/xml/ShippingInvoiceMapper.xml @@ -29,4 +29,10 @@ FROM platform_order_content p WHERE p.platform_order_id = #{platformOrderId} + \ No newline at end of file diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/EmailService.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/EmailService.java index 732b6a057..373247bd8 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/EmailService.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/EmailService.java @@ -5,10 +5,12 @@ import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer; import javax.mail.MessagingException; import javax.mail.Session; import java.io.IOException; +import java.util.Map; import java.util.Properties; public interface EmailService { public void sendSimpleMessage(String recipient, String subject, String text, Session session) throws MessagingException; + public void newSendSimpleMessage(String recipient, String subject, String templateName, Map templateModel) throws MessagingException; public void sendMessageWithAttachment(String recipient, String subject, String text, String attachment, Session session) throws MessagingException, IOException; public Properties getMailSender(); public FreeMarkerConfigurer freemarkerClassLoaderConfig() throws IOException; diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/IBalanceService.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/IBalanceService.java index 3e76fe224..e8be3c900 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/IBalanceService.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/IBalanceService.java @@ -1,7 +1,10 @@ package org.jeecg.modules.business.service; +import org.apache.commons.lang3.tuple.Pair; import org.jeecg.modules.business.entity.Balance; import com.baomidou.mybatisplus.extension.service.IService; +import org.jeecg.modules.business.entity.Client; +import org.jeecg.modules.business.vo.BalanceData; import org.jeecg.modules.business.vo.InvoiceMetaData; import java.math.BigDecimal; @@ -37,4 +40,11 @@ public interface IBalanceService extends IService { void editBalance(String operationId, String operationType, String clientId, BigDecimal amount, String currencyId) throws Exception; void deleteBatchBalance(List operationIds, String operationType); + + /** + * Get low balance clients from client list + * @param metaDataList list of meta data + * @return + */ + List getLowBalanceClients(List metaDataList); } diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/IClientService.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/IClientService.java index c787af1a3..0a991e808 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/IClientService.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/IClientService.java @@ -40,7 +40,7 @@ public interface IClientService extends IService { public void delBatchMain (Collection idList); public String getClientEntity(String id); public Map getClientsEntity(List ids); - public String getClientByInternalCode(String code); + public String getClientIdByCode(String code); /** * Get current user's client information * @return client or null if current user's role is not client diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/IPlatformOrderContentService.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/IPlatformOrderContentService.java index 08ab8ab7b..b0555ade8 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/IPlatformOrderContentService.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/IPlatformOrderContentService.java @@ -54,4 +54,5 @@ public interface IPlatformOrderContentService extends IService invoiceNumbers); + } diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/IPlatformOrderService.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/IPlatformOrderService.java index 1d31784a4..d717ec283 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/IPlatformOrderService.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/IPlatformOrderService.java @@ -2,6 +2,7 @@ package org.jeecg.modules.business.service; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.service.IService; +import org.jeecg.modules.business.controller.UserException; import org.jeecg.modules.business.entity.*; import org.jeecg.modules.business.vo.PlatformOrderQuantity; import org.jeecg.modules.business.vo.SkuQuantity; @@ -54,19 +55,19 @@ public interface IPlatformOrderService extends IService { void processedPlatformOrderPage(IPage page); - OrdersStatisticData getPlatformOrdersStatisticData(List orderIds); + OrdersStatisticData getPlatformOrdersStatisticData(List orderIds) throws UserException; List selectByMainId(String mainId); List selectClientVersionByMainId(String mainId); - PurchaseConfirmation confirmPurchaseByPlatformOrder(List platformOrderIdList); + PurchaseConfirmation confirmPurchaseByPlatformOrder(List platformOrderIdList) throws UserException; - PurchaseConfirmation confirmPurchaseBySkuQuantity(List skuIDQuantityMap); + PurchaseConfirmation confirmPurchaseBySkuQuantity(List skuIDQuantityMap) throws UserException; - PurchaseConfirmation confirmPurchaseBySkuQuantity(ClientInfo clientInfo, List skuIDQuantityMap); + PurchaseConfirmation confirmPurchaseBySkuQuantity(ClientInfo clientInfo, List skuIDQuantityMap) throws UserException; - List searchPurchaseOrderDetail(List skuQuantities); + List searchPurchaseOrderDetail(List skuQuantities) throws UserException; OrderQuantity queryOrderQuantities(); @@ -199,4 +200,5 @@ public interface IPlatformOrderService extends IService { * @return */ List fetchEmptyLogisticChannelOrders(String startDate, String endDate); + } diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/IPurchaseOrderService.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/IPurchaseOrderService.java index 02287cf41..de8628a1c 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/IPurchaseOrderService.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/IPurchaseOrderService.java @@ -2,6 +2,7 @@ package org.jeecg.modules.business.service; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.service.IService; +import org.jeecg.modules.business.controller.UserException; import org.jeecg.modules.business.domain.purchase.invoice.InvoiceData; import org.jeecg.modules.business.entity.*; import org.jeecg.modules.business.vo.SkuQuantity; @@ -10,6 +11,7 @@ import org.springframework.web.multipart.MultipartFile; import java.io.IOException; import java.io.Serializable; +import java.math.BigDecimal; import java.net.URISyntaxException; import java.util.Collection; import java.util.List; @@ -49,7 +51,7 @@ public interface IPurchaseOrderService extends IService { */ void setPageForCurrentClient(IPage page); - String addPurchase(List skuQuantities); + String addPurchase(List skuQuantities) throws UserException; /** * Add a new purchase. The purchase contains sku and its quantity indicated by @@ -65,10 +67,10 @@ public interface IPurchaseOrderService extends IService { * @return the new purchase order identifier */ @Transactional - String addPurchase(List SkuQuantity, List orderIDs); + String addPurchase(List SkuQuantity, List orderIDs) throws UserException; @Transactional - String addPurchase(String username, Client client, String invoiceNumber, List skuQuantities, Map> platformOrderIDs); + String addPurchase(String username, Client client, String invoiceNumber, List skuQuantities, Map> platformOrderIDs) throws UserException; void savePaymentDocumentForPurchase(String purchaseID, MultipartFile in) throws IOException; @@ -105,4 +107,10 @@ public interface IPurchaseOrderService extends IService { InvoiceData makeInvoice(String purchaseID) throws IOException, URISyntaxException; byte[] getInvoiceByte(String invoiceCode) throws IOException; + + BigDecimal getPurchaseFeesByInvoiceCode(String invoiceCode); + + void cancelInvoice(String invoiceNumber); + + void cancelBatchInvoice(List invoiceNumbers); } diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/IShippingInvoiceService.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/IShippingInvoiceService.java index 9f0f21276..940e758dd 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/IShippingInvoiceService.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/IShippingInvoiceService.java @@ -1,9 +1,6 @@ package org.jeecg.modules.business.service; -import org.jeecg.modules.business.entity.Client; -import org.jeecg.modules.business.entity.PlatformOrder; -import org.jeecg.modules.business.entity.PlatformOrderContent; -import org.jeecg.modules.business.entity.ShippingInvoice; +import org.jeecg.modules.business.entity.*; import com.baomidou.mybatisplus.extension.service.IService; import java.io.Serializable; @@ -42,4 +39,5 @@ public interface IShippingInvoiceService extends IService { public List getPlatformOrder(String invoiceNumber); public List getPlatformOrderContent(String platformOrderId); public Client getShopOwnerFromInvoiceNumber(String invoiceNumber); + Currency getInvoiceCurrencyByCode(String invoiceCode); } diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/PlatformOrderShippingInvoiceService.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/PlatformOrderShippingInvoiceService.java index 4c562f3eb..446f101a4 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/PlatformOrderShippingInvoiceService.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/PlatformOrderShippingInvoiceService.java @@ -17,9 +17,11 @@ import org.jeecg.modules.business.vo.*; import org.jetbrains.annotations.NotNull; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; +import org.springframework.core.env.Environment; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import javax.mail.MessagingException; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; @@ -52,6 +54,8 @@ public class PlatformOrderShippingInvoiceService { @Autowired ClientMapper clientMapper; @Autowired + EmailService emailService; + @Autowired ShopMapper shopMapper; @Autowired LogisticChannelPriceMapper logisticChannelPriceMapper; @@ -81,7 +85,8 @@ public class PlatformOrderShippingInvoiceService { ISavRefundWithDetailService savRefundWithDetailService; @Autowired ISavRefundService savRefundService; - + @Autowired + Environment env; @Value("${jeecg.path.shippingTemplatePath_EU}") private String SHIPPING_INVOICE_TEMPLATE_EU; @@ -140,6 +145,8 @@ public class PlatformOrderShippingInvoiceService { } public Period getValidOrderTimePeriod(List shopIDs, List erpStatuses) { Date begin = platformOrderMapper.findEarliestUninvoicedPlatformOrderTime(shopIDs, erpStatuses); + if(begin == null) + return null; ZoneId shanghai = ZoneId.of("Asia/Shanghai"); ZoneId paris = ZoneId.of("Europe/Paris"); LocalDateTime ldt = LocalDateTime.ofInstant(begin.toInstant(), shanghai); @@ -164,27 +171,21 @@ public class PlatformOrderShippingInvoiceService { * @throws IOException exception related to invoice file IO. */ @Transactional - public InvoiceMetaData makeInvoice(ShippingInvoiceParam param) throws UserException, ParseException, IOException { + public InvoiceMetaData makeInvoice(ShippingInvoiceParam param, String ... user) throws UserException, ParseException, IOException { // Creates factory ShippingInvoiceFactory factory = new ShippingInvoiceFactory( platformOrderService, clientMapper, shopMapper, logisticChannelMapper, logisticChannelPriceMapper, platformOrderContentService, skuDeclaredValueService, countryService, exchangeRatesMapper, - purchaseOrderService, purchaseOrderContentMapper, skuPromotionHistoryMapper, savRefundService, savRefundWithDetailService); - Subject subject = null; - try { - subject = SecurityUtils.getSubject(); - } - catch (Exception e) { - log.error("Error while getting subject", e); - } - String username = subject == null ? "admin" : ((LoginUser) subject.getPrincipal()).getUsername(); + purchaseOrderService, purchaseOrderContentMapper, skuPromotionHistoryMapper, savRefundService, savRefundWithDetailService, emailService, env); + String username = user.length > 0 ? user[0] : ((LoginUser) SecurityUtils.getSubject().getPrincipal()).getUsername(); // Creates invoice by factory ShippingInvoice invoice = factory.createInvoice(param.clientID(), param.shopIDs(), param.start(), param.end(), param.getErpStatuses(), - param.getWarehouses() + param.getWarehouses(), + param.getBalance() ); // Chooses invoice template based on client's preference on currency return getInvoiceMetaData(username, invoice); @@ -206,7 +207,7 @@ public class PlatformOrderShippingInvoiceService { ShippingInvoiceFactory factory = new ShippingInvoiceFactory( platformOrderService, clientMapper, shopMapper, logisticChannelMapper, logisticChannelPriceMapper, platformOrderContentService, skuDeclaredValueService, countryService, exchangeRatesMapper, - purchaseOrderService, purchaseOrderContentMapper, skuPromotionHistoryMapper, savRefundService, savRefundWithDetailService); + purchaseOrderService, purchaseOrderContentMapper, skuPromotionHistoryMapper, savRefundService, savRefundWithDetailService, emailService, env); String username = ((LoginUser) SecurityUtils.getSubject().getPrincipal()).getUsername(); // Creates invoice by factory ShippingInvoice invoice = factory.createShippingInvoice(param.clientID(), param.orderIds(), param.getType(), param.getStart(), param.getEnd()); @@ -224,15 +225,15 @@ public class PlatformOrderShippingInvoiceService { * @throws IOException exception related to invoice file IO. */ @Transactional - public InvoiceMetaData makeCompleteInvoice(ShippingInvoiceOrderParam param) throws UserException, ParseException, IOException { + public InvoiceMetaData makeCompleteInvoice(ShippingInvoiceOrderParam param) throws UserException, ParseException, IOException, MessagingException { // Creates factory ShippingInvoiceFactory factory = new ShippingInvoiceFactory( platformOrderService, clientMapper, shopMapper, logisticChannelMapper, logisticChannelPriceMapper, platformOrderContentService, skuDeclaredValueService, countryService, exchangeRatesMapper, - purchaseOrderService, purchaseOrderContentMapper, skuPromotionHistoryMapper, savRefundService, savRefundWithDetailService); + purchaseOrderService, purchaseOrderContentMapper, skuPromotionHistoryMapper, savRefundService, savRefundWithDetailService, emailService, env); String username = ((LoginUser) SecurityUtils.getSubject().getPrincipal()).getUsername(); // Creates invoice by factory - CompleteInvoice invoice = factory.createCompleteShippingInvoice(username, param.clientID(), param.orderIds(), param.getType(), param.getStart(), param.getEnd()); + CompleteInvoice invoice = factory.createCompleteShippingInvoice(username, param.clientID(), null, param.orderIds(), param.getType(), param.getStart(), param.getEnd()); return getInvoiceMetaData(username, invoice); } @@ -246,25 +247,25 @@ public class PlatformOrderShippingInvoiceService { * @throws IOException */ @Transactional - public InvoiceMetaData makeCompleteInvoicePostShipping(ShippingInvoiceParam param, String method) throws UserException, ParseException, IOException { + public InvoiceMetaData makeCompleteInvoicePostShipping(ShippingInvoiceParam param, String method, String ... user) throws UserException, ParseException, IOException, MessagingException { // Creates factory ShippingInvoiceFactory factory = new ShippingInvoiceFactory( platformOrderService, clientMapper, shopMapper, logisticChannelMapper, logisticChannelPriceMapper, platformOrderContentService, skuDeclaredValueService, countryService, exchangeRatesMapper, - purchaseOrderService, purchaseOrderContentMapper, skuPromotionHistoryMapper, savRefundService, savRefundWithDetailService); - String username = ((LoginUser) SecurityUtils.getSubject().getPrincipal()).getUsername(); + purchaseOrderService, purchaseOrderContentMapper, skuPromotionHistoryMapper, savRefundService, savRefundWithDetailService, emailService, env); + String username = user.length > 0 ? user[0] : ((LoginUser) SecurityUtils.getSubject().getPrincipal()).getUsername(); List platformOrderList; if(method.equals("post")) { //On récupère les commandes entre 2 dates d'expédition avec un status 3 platformOrderList = platformOrderMapper.fetchUninvoicedShippedOrderIDInShops(param.getStart(), param.getEnd(), param.shopIDs(), param.getWarehouses()); } else { // On récupère les commandes entre 2 dates de commandes avec un status (1,2) ou (1,2,3) - platformOrderList = platformOrderMapper.fetchUninvoicedShippedOrderIDInShopsAndOrderTime(param.getStart(), param.getEnd(), param.shopIDs(), param.getErpStatuses(), param.getWarehouses()); + platformOrderList = platformOrderMapper.fetchUninvoicedOrderIDInShopsAndOrderTime(param.getStart(), param.getEnd(), param.shopIDs(), param.getErpStatuses(), param.getWarehouses()); } // on récupère seulement les ID des commandes List orderIds = platformOrderList.stream().map(PlatformOrder::getId).collect(Collectors.toList()); // Creates invoice by factory - CompleteInvoice invoice = factory.createCompleteShippingInvoice(username, param.clientID(), orderIds, method, param.getStart(), param.getEnd()); + CompleteInvoice invoice = factory.createCompleteShippingInvoice(username, param.clientID(), param.getBalance() ,orderIds, method, param.getStart(), param.getEnd()); return getInvoiceMetaData(username, invoice); } @NotNull @@ -316,7 +317,7 @@ public class PlatformOrderShippingInvoiceService { ShippingInvoiceFactory factory = new ShippingInvoiceFactory( platformOrderService, clientMapper, shopMapper, logisticChannelMapper, logisticChannelPriceMapper, platformOrderContentService, skuDeclaredValueService, countryService, exchangeRatesMapper, - purchaseOrderService, purchaseOrderContentMapper, skuPromotionHistoryMapper, savRefundService, savRefundWithDetailService); + purchaseOrderService, purchaseOrderContentMapper, skuPromotionHistoryMapper, savRefundService, savRefundWithDetailService, emailService, env); return factory.getEstimations(errorMessages); } @@ -331,7 +332,7 @@ public class PlatformOrderShippingInvoiceService { ShippingInvoiceFactory factory = new ShippingInvoiceFactory( platformOrderService, clientMapper, shopMapper, logisticChannelMapper, logisticChannelPriceMapper, platformOrderContentService, skuDeclaredValueService, countryService, exchangeRatesMapper, - purchaseOrderService, purchaseOrderContentMapper, skuPromotionHistoryMapper, savRefundService, savRefundWithDetailService); + purchaseOrderService, purchaseOrderContentMapper, skuPromotionHistoryMapper, savRefundService, savRefundWithDetailService, emailService, env); return factory.getEstimations(clientId, orderIds, errorMessages); } @@ -483,7 +484,7 @@ public class PlatformOrderShippingInvoiceService { "\nclient : " + entry.getKey() + "\nbetween dates : [" + start + "] --- [" + end + "]"); try { - ShippingInvoiceParam param = new ShippingInvoiceParam(entry.getKey(), entry.getValue(), start, end, Collections.singletonList(3), Arrays.asList("0", "1")); + ShippingInvoiceParam param = new ShippingInvoiceParam(entry.getKey(), null, entry.getValue(), start, end, Collections.singletonList(3), Arrays.asList("0", "1")); InvoiceMetaData metaData; if(invoiceType == 0) { metaData = makeInvoice(param); @@ -498,6 +499,62 @@ public class PlatformOrderShippingInvoiceService { String internalCode = clientMapper.selectById(entry.getKey()).getInternalCode(); invoiceList.add(new InvoiceMetaData("", "error", internalCode, entry.getKey(), e.getMessage())); log.error(e.getMessage()); + } catch (MessagingException e) { + throw new RuntimeException(e); + } + System.gc(); + } + return invoiceList; + } + + /** + * make shipping invoice by client and type (shipping or complete) and invoice only if client has sufficient balance + * @param balanceDataList list of balance data with client info, balance and currency + * @param invoiceType shipping invoice or complete invoice + * @return list of filename (invoices and details) + */ + @Transactional + public List breakdownInvoiceClientByTypeAndBalance(List balanceDataList, int invoiceType) { + Map> clientShopIDsMap = new HashMap<>(); + List invoiceList = new ArrayList<>(); + for(BalanceData data: balanceDataList) { + String id = data.getClient().getId(); + clientShopIDsMap.put(data, shopService.listIdByClient(id)); + } + for(Map.Entry> entry: clientShopIDsMap.entrySet()) { + String clientId = entry.getKey().getClient().getId(); + Period period = getValidOrderTimePeriod(entry.getValue(), Collections.singletonList(1)); + if(period == null || !period.isValid()) { + String internalCode = entry.getKey().getClient().getInternalCode(); + invoiceList.add(new InvoiceMetaData("", "error", internalCode, clientId, "No order to invoice.")); + continue; + } + System.out.println("Period: [" + period.start() + " - " + period.end() + "]"); + Calendar calendar = Calendar.getInstance(); + calendar.setTime(period.start()); + String start = calendar.get(Calendar.YEAR) + "-" + (calendar.get(Calendar.MONTH)+1 < 10 ? "0" : "") + (calendar.get(Calendar.MONTH)+1) + "-" + (calendar.get(Calendar.DAY_OF_MONTH) < 10 ? "0" : "") + (calendar.get(Calendar.DAY_OF_MONTH)); + calendar.setTime(period.end()); + String end = calendar.get(Calendar.YEAR) + "-" + (calendar.get(Calendar.MONTH)+1 < 10 ? "0" : "") + (calendar.get(Calendar.MONTH)+1) + "-" + (calendar.get(Calendar.DAY_OF_MONTH)+1 < 10 ? "0" : "") + (calendar.get(Calendar.DAY_OF_MONTH)+1); + log.info( "Invoicing : " + (invoiceType == 0 ? "Shipping Invoice" : "Complete Shipping Invoice") + + "\nclient : " + entry.getKey() + + "\nbetween dates : [" + start + "] --- [" + end + "]"); + try { + ShippingInvoiceParam param = new ShippingInvoiceParam(clientId, entry.getKey().getBalance(), entry.getValue(), start, end, Collections.singletonList(1), Arrays.asList("0", "1")); + InvoiceMetaData metaData; + if(invoiceType == 0) { + metaData = makeInvoice(param, "system"); + balanceService.updateBalance(clientId, metaData.getInvoiceCode(), "shipping"); + } + else { + metaData = makeCompleteInvoicePostShipping(param, "pre-shipping", "system"); + balanceService.updateBalance(clientId, metaData.getInvoiceCode(), "complete"); + } + platformOrderMapper.updateErpStatusByCode(metaData.getInvoiceCode(), 2); + invoiceList.add(metaData); + } catch (UserException | IOException | ParseException | MessagingException e) { + String internalCode = entry.getKey().getClient().getInternalCode(); + invoiceList.add(new InvoiceMetaData("", "error", internalCode, clientId, e.getMessage())); + log.error(e.getMessage()); } System.gc(); } diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/impl/BalanceServiceImpl.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/impl/BalanceServiceImpl.java index 96ad6ce06..bbd270076 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/impl/BalanceServiceImpl.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/impl/BalanceServiceImpl.java @@ -1,15 +1,14 @@ package org.jeecg.modules.business.service.impl; import lombok.extern.slf4j.Slf4j; -import org.jeecg.modules.business.entity.Balance; -import org.jeecg.modules.business.entity.PlatformOrder; -import org.jeecg.modules.business.entity.PlatformOrderContent; -import org.jeecg.modules.business.entity.ShippingInvoice; +import org.apache.commons.lang3.tuple.Pair; +import org.jeecg.modules.business.entity.*; import org.jeecg.modules.business.mapper.BalanceMapper; -import org.jeecg.modules.business.service.IBalanceService; -import org.jeecg.modules.business.service.ICurrencyService; -import org.jeecg.modules.business.service.IPlatformOrderService; -import org.jeecg.modules.business.service.IShippingInvoiceService; +import org.jeecg.modules.business.mapper.ClientCategoryMapper; +import org.jeecg.modules.business.mapper.ClientMapper; +import org.jeecg.modules.business.service.*; +import org.jeecg.modules.business.vo.BalanceData; +import org.jeecg.modules.business.vo.InvoiceMetaData; import org.jeecg.modules.system.entity.SysUser; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -17,6 +16,7 @@ import org.springframework.stereotype.Service; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import java.math.BigDecimal; +import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @@ -33,11 +33,17 @@ public class BalanceServiceImpl extends ServiceImpl impl @Autowired private BalanceMapper balanceMapper; @Autowired + private ClientCategoryMapper clientCategoryMapper; + @Autowired + private ClientMapper clientMapper; + @Autowired private ICurrencyService currencyService; @Autowired private IPlatformOrderService platformOrderService; @Autowired - IShippingInvoiceService iShippingInvoiceService; + private IPurchaseOrderService purchaseOrderService; + @Autowired + IShippingInvoiceService shippingInvoiceService; @Override public BigDecimal getBalanceByClientIdAndCurrency(String clientId, String currency) { return balanceMapper.getBalanceByClientIdAndCurrency(clientId, currency); @@ -47,20 +53,13 @@ public class BalanceServiceImpl extends ServiceImpl impl public void updateBalance(String clientId, String invoiceCode, String invoiceType) { // balance update - ShippingInvoice invoice = iShippingInvoiceService.getShippingInvoice(invoiceCode); + ShippingInvoice invoice = shippingInvoiceService.getShippingInvoice(invoiceCode); String currency = currencyService.getCodeById(invoice.getCurrencyId()); BigDecimal previousBalance = getBalanceByClientIdAndCurrency(clientId, currency); BigDecimal currentBalance = previousBalance.subtract(invoice.getFinalAmount()); if(invoiceType.equals("complete")) { - List orderIds = iShippingInvoiceService.getPlatformOrder(invoiceCode).stream().map(PlatformOrder::getId).collect(Collectors.toList()); - Map> orderMap = platformOrderService.fetchOrderData(orderIds); - BigDecimal purchaseFees = BigDecimal.ZERO; - for(Map.Entry> entry : orderMap.entrySet()) { - for(PlatformOrderContent content : entry.getValue()) { - purchaseFees = purchaseFees.add(content.getPurchaseFee()); - } - } - currentBalance = currentBalance.add(purchaseFees); + BigDecimal purchaseFees = purchaseOrderService.getPurchaseFeesByInvoiceCode(invoiceCode); + currentBalance = currentBalance.subtract(purchaseFees); } SysUser sysUser = new SysUser(); Balance balance = Balance.of(sysUser.getUsername(), clientId, invoice.getCurrencyId(), Balance.OperationType.Debit.name(), invoice.getId(), currentBalance); @@ -86,6 +85,7 @@ public class BalanceServiceImpl extends ServiceImpl impl public void deleteBatchBalance(List operationIds, String operationType) { balanceMapper.deleteBatchBalance(operationIds, operationType); } + @Override public void editBalance(String operationId, String operationType, String clientId, BigDecimal amount, String currencyId) throws Exception { log.info("editing balance"); @@ -105,4 +105,20 @@ public class BalanceServiceImpl extends ServiceImpl impl balanceMapper.insert(newBalance); } + @Override + public List getLowBalanceClients(List metaDataList) { + List lowBalanceDataList = new ArrayList<>(); + for(InvoiceMetaData metaData : metaDataList) { + Client client = clientMapper.getClientByCode(metaData.getInternalCode()); + Currency currency = shippingInvoiceService.getInvoiceCurrencyByCode(metaData.getInvoiceCode()); + BigDecimal balance = getBalanceByClientIdAndCurrency(client.getId(), currency.getCode()); + BigDecimal balanceThreshold = client.getBalanceThreshold() == null ? + clientCategoryMapper.getBalanceThresholdByCategoryId(client.getClientCategoryId()) : client.getBalanceThreshold(); + if(balance.compareTo(balanceThreshold) < 0) { + lowBalanceDataList.add(new BalanceData(client, currency.getCode(), balance)); + } + } + return lowBalanceDataList; + } + } diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/impl/ClientServiceImpl.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/impl/ClientServiceImpl.java index 5f451350d..9a141aa2e 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/impl/ClientServiceImpl.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/impl/ClientServiceImpl.java @@ -133,7 +133,7 @@ public class ClientServiceImpl extends ServiceImpl impleme } @Override - public String getClientByInternalCode(String code) { - return clientMapper.getClientByInternalCode(code); + public String getClientIdByCode(String code) { + return clientMapper.getClientIdByCode(code); } } diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/impl/EmailServiceImpl.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/impl/EmailServiceImpl.java index 9b4184e45..6af2ec090 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/impl/EmailServiceImpl.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/impl/EmailServiceImpl.java @@ -3,25 +3,32 @@ package org.jeecg.modules.business.service.impl; import freemarker.cache.FileTemplateLoader; import freemarker.cache.TemplateLoader; import freemarker.template.Configuration; +import freemarker.template.Template; +import lombok.extern.slf4j.Slf4j; import org.jeecg.modules.business.service.EmailService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.env.Environment; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.springframework.ui.freemarker.FreeMarkerTemplateUtils; import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer; import javax.mail.*; import javax.mail.internet.*; import java.io.File; import java.io.IOException; +import java.util.Map; import java.util.Objects; import java.util.Properties; +@Slf4j @Service public class EmailServiceImpl implements EmailService { @Autowired Environment env; + @Autowired + FreeMarkerConfigurer freemarkerConfigurer; @Override @Transactional public Properties getMailSender() { @@ -49,6 +56,41 @@ public class EmailServiceImpl implements EmailService { Transport.send(message); } + + @Override + @Transactional + public void newSendSimpleMessage(String recipient, String subject, String templateName, Map templateModel) { + Properties prop = getMailSender(); + Session session = Session.getInstance(prop, new Authenticator() { + @Override + protected PasswordAuthentication getPasswordAuthentication() { + return new PasswordAuthentication(env.getProperty("spring.mail.username"), env.getProperty("spring.mail.password")); + } + }); + try { + freemarkerConfigurer = freemarkerClassLoaderConfig(); + Template freemarkerTemplate = freemarkerConfigurer.getConfiguration() + .getTemplate(templateName); + String htmlBody = FreeMarkerTemplateUtils.processTemplateIntoString(freemarkerTemplate, templateModel); + Message message = new MimeMessage(session); + + message.setFrom(new InternetAddress(Objects.requireNonNull(env.getProperty("spring.mail.username")))); + message.setRecipient(Message.RecipientType.TO, InternetAddress.parse(recipient)[0]); + if(!recipient.equals(env.getProperty("spring.mail.username"))) + message.setRecipient(Message.RecipientType.CC, InternetAddress.parse(Objects.requireNonNull(env.getProperty("spring.mail.username")))[0]); + + message.setSubject(subject); + message.setContent(htmlBody, "text/html; charset=utf-8"); + + Transport.send(message); + + log.info("Mail sent successfully"); + } catch (Exception e) { + log.error("Error while sending mail in VipInvoicingJob", e); + e.printStackTrace(); + } + + } @Override @Transactional public void sendMessageWithAttachment(String recipient, String subject, String text, String attachment, Session session) throws MessagingException, IOException { diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/impl/PlatformOrderServiceImpl.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/impl/PlatformOrderServiceImpl.java index a3753b85b..1fc6a3160 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/impl/PlatformOrderServiceImpl.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/impl/PlatformOrderServiceImpl.java @@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.toolkit.SqlHelper; import lombok.extern.slf4j.Slf4j; +import org.jeecg.modules.business.controller.UserException; import org.jeecg.modules.business.entity.*; import org.jeecg.modules.business.mapper.ExchangeRatesMapper; import org.jeecg.modules.business.mapper.PlatformOrderContentMapper; @@ -13,6 +14,7 @@ import org.jeecg.modules.business.service.IClientService; import org.jeecg.modules.business.service.IPlatformOrderService; import org.jeecg.modules.business.service.IShippingFeesWaiverProductService; import org.jeecg.modules.business.vo.PlatformOrderQuantity; +import org.jeecg.modules.business.vo.SkuDetail; import org.jeecg.modules.business.vo.SkuQuantity; import org.jeecg.modules.business.vo.SkuShippingFeesWaiver; import org.jeecg.modules.business.vo.clientPlatformOrder.ClientPlatformOrderPage; @@ -182,7 +184,7 @@ public class PlatformOrderServiceImpl extends ServiceImpl orderIds) { + public OrdersStatisticData getPlatformOrdersStatisticData(List orderIds) throws UserException { List skuIDQuantityMap = platformOrderContentMap.searchOrderContent(orderIds); List data = searchPurchaseOrderDetail(skuIDQuantityMap); return OrdersStatisticData.makeData(data, null); @@ -200,14 +202,14 @@ public class PlatformOrderServiceImpl extends ServiceImpl platformOrderIdList) { + public PurchaseConfirmation confirmPurchaseByPlatformOrder(List platformOrderIdList) throws UserException { List skuIDQuantityMap = platformOrderContentMap.searchOrderContent(platformOrderIdList); return confirmPurchaseBySkuQuantity(skuIDQuantityMap); } @Override - public PurchaseConfirmation confirmPurchaseBySkuQuantity(List skuIDQuantityMap) { + public PurchaseConfirmation confirmPurchaseBySkuQuantity(List skuIDQuantityMap) throws UserException { Client client = clientService.getCurrentClient(); ClientInfo clientInfo = new ClientInfo(client); return new PurchaseConfirmation(clientInfo, searchPurchaseOrderDetail(skuIDQuantityMap), @@ -215,13 +217,13 @@ public class PlatformOrderServiceImpl extends ServiceImpl skuIDQuantityMap) { + public PurchaseConfirmation confirmPurchaseBySkuQuantity(ClientInfo clientInfo, List skuIDQuantityMap) throws UserException { return new PurchaseConfirmation(clientInfo, searchPurchaseOrderDetail(skuIDQuantityMap), getShippingFeesWaiverMap(skuIDQuantityMap.stream().map(SkuQuantity::getID).collect(toList()))); } @Override - public List searchPurchaseOrderDetail(List skuQuantities) { + public List searchPurchaseOrderDetail(List skuQuantities) throws UserException { BigDecimal eurToRmb = exchangeRatesMapper.getLatestExchangeRate("EUR", "RMB"); // convert list of (ID, quantity) to map between ID and quantity Map skuQuantity = @@ -236,7 +238,14 @@ public class PlatformOrderServiceImpl extends ServiceImpl skuList = new ArrayList<>(skuQuantity.keySet()); - List details = platformOrderContentMap.searchSkuDetail(skuList).stream() + List skuDetails = platformOrderContentMap.searchSkuDetail(skuList); + for(SkuDetail detail : skuDetails) { + if(detail.getPrice().getId() == null || detail.getPrice().getPrice() == null) { + throw new UserException("SKU " + detail.getSkuId() + " has no price or price id"); + } + } + System.out.println("Breakpoint"); + List details = skuDetails.stream() .map( skuDetail -> new OrderContentDetail( skuDetail, diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/impl/ShippingInvoiceServiceImpl.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/impl/ShippingInvoiceServiceImpl.java index a057097f8..cde94b7fb 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/impl/ShippingInvoiceServiceImpl.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/impl/ShippingInvoiceServiceImpl.java @@ -2,10 +2,7 @@ package org.jeecg.modules.business.service.impl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import lombok.extern.slf4j.Slf4j; -import org.jeecg.modules.business.entity.Client; -import org.jeecg.modules.business.entity.PlatformOrder; -import org.jeecg.modules.business.entity.PlatformOrderContent; -import org.jeecg.modules.business.entity.ShippingInvoice; +import org.jeecg.modules.business.entity.*; import org.jeecg.modules.business.mapper.ShippingInvoiceMapper; import org.jeecg.modules.business.service.IShippingInvoiceService; import org.springframework.beans.factory.annotation.Autowired; @@ -70,6 +67,11 @@ public class ShippingInvoiceServiceImpl extends ServiceImpl skuQuantities) { + public String addPurchase(List skuQuantities) throws UserException { return addPurchase(skuQuantities, Collections.emptyList()); } @@ -228,7 +229,7 @@ public class PurchaseOrderServiceImpl extends ServiceImpl skuQuantities, List platformOrderIDs) { + public String addPurchase(List skuQuantities, List platformOrderIDs) throws UserException { Objects.requireNonNull(platformOrderIDs); Client client = clientService.getCurrentClient(); @@ -318,7 +319,7 @@ public class PurchaseOrderServiceImpl extends ServiceImpl skuQuantities, - Map> orderAndContent) { + Map> orderAndContent) throws UserException { Objects.requireNonNull(orderAndContent); List details = platformOrderService.searchPurchaseOrderDetail(skuQuantities); @@ -470,4 +471,19 @@ public class PurchaseOrderServiceImpl extends ServiceImpl invoiceNumbers) { + purchaseOrderMapper.deleteBatchInvoice(invoiceNumbers); + } } diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/vo/BalanceData.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/vo/BalanceData.java new file mode 100644 index 000000000..244798d04 --- /dev/null +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/vo/BalanceData.java @@ -0,0 +1,13 @@ +package org.jeecg.modules.business.vo; + +import lombok.Data; +import org.jeecg.modules.business.entity.Client; + +import java.math.BigDecimal; + +@Data +public class BalanceData { + private final Client client; + private final String currency; + private final BigDecimal balance; +} diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/vo/ShippingInvoiceParam.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/vo/ShippingInvoiceParam.java index 12eb900b0..bae725c5d 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/vo/ShippingInvoiceParam.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/vo/ShippingInvoiceParam.java @@ -1,16 +1,18 @@ package org.jeecg.modules.business.vo; -import com.alibaba.fastjson.annotation.JSONField; import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; +import java.math.BigDecimal; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.List; - +@Data public class ShippingInvoiceParam { private final String clientID; + private final BigDecimal balance; private final List shopIDs; private final String start; private final String end; @@ -19,12 +21,14 @@ public class ShippingInvoiceParam { private final static SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd"); public ShippingInvoiceParam(@JsonProperty("clientID") String clientID, + @JsonProperty("balance") BigDecimal balance, @JsonProperty("shopIDs") List shopIDs, @JsonProperty("start") String start, @JsonProperty("end") String end, @JsonProperty("erpStatuses") List erpStatuses, @JsonProperty("warehouses") List warehouses) { this.clientID = clientID; + this.balance = balance; this.shopIDs = shopIDs; this.start = start; this.end = end; @@ -47,16 +51,6 @@ public class ShippingInvoiceParam { public Date end() throws ParseException { return format.parse(end); } - public String getStart() { - return this.start; - } - public String getEnd() { - return this.end; - } - public List getErpStatuses() { return erpStatuses; } - public List getWarehouses() { - return warehouses; - } @Override public String toString() { return "ShippingInvoiceParam{" + clientID + diff --git a/jeecg-module-system/jeecg-system-biz/src/main/resources/templates/breakdownInvoiceMail.ftl b/jeecg-module-system/jeecg-system-biz/src/main/resources/templates/breakdownInvoiceMail.ftl index 5937bc5d4..bbe5672f8 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/resources/templates/breakdownInvoiceMail.ftl +++ b/jeecg-module-system/jeecg-system-biz/src/main/resources/templates/breakdownInvoiceMail.ftl @@ -1,98 +1,22 @@ - - - - - - - - - - - - - - - - - - -
    - - logo - -
    - - - - - - - - - - - - <#list errors as error> - - - - - - - - - - - - - - -
    Cher collègue,
    Vous trouverez en pièce-jointe une archive de l'ensemble des factures générées :
    Erreurs : - <#if errors?size = 0> - No error - -
    - Error: ${error.invoiceEntity} - ${error.errorMsg} -
    Merci d’utiliser nos services.
    Cordialement
    L’équipe WIA Sourcing.
    -
    - - - - - - - - - - - - - - - -
    Ce message a été envoyé automatiquement. Merci de ne pas répondre. Ce message et ainsi que toutes les pièces jointes sont confidentielles.
    Si vous avez reçu ce message par erreur, merci de nous avertir immédiatement et de détruire ce message.
    Service client :
    Pour obtenir plus d’informations concernant nos services, veuillez nous contacter à l’adresse ci-dessous ou en visitant notre site web.
    - - - - - - - - -
    Nous contacterNotre site web
    - - - - - - - - - - - - -
    WIA SOURCING
    © 2018/2023 par WIA Sourcing Agency.
    TOUS DROITS RÉSERVÉS©
    -
    - - \ No newline at end of file +<#include "components/header.ftl"> + + Cher collègue, + + + Vous trouverez en pièce-jointe une archive de l'ensemble des factures générées : + + + Erreurs : + <#if errors?size = 0> + No error + + + + <#list errors as error> + + + Error: ${error.invoiceEntity} - ${error.errorMsg} + + + +<#include "components/footer.ftl"> \ No newline at end of file diff --git a/jeecg-module-system/jeecg-system-biz/src/main/resources/templates/client/confirmedClientsInvoicingJobReport.ftl b/jeecg-module-system/jeecg-system-biz/src/main/resources/templates/client/confirmedClientsInvoicingJobReport.ftl new file mode 100644 index 000000000..1f96f9aec --- /dev/null +++ b/jeecg-module-system/jeecg-system-biz/src/main/resources/templates/client/confirmedClientsInvoicingJobReport.ftl @@ -0,0 +1,56 @@ +<#include "../components/header.ftl"> + + Cher(e) ${client.firstName} ${client.surname}, + + + Une ou plusieurs commandes n'ont pas pu être facturées en raison d'un solde insuffisant : + + + <#if errors?size = 0> +

    No error

    + <#elseif chronologicalOrder=="1"> +

    Les commandes à partir du numéro ${errors[0].platformOrderNumber} - ${errors[0].orderTime?datetime?string('dd-MM-yyyy')} n'ont pas été facturées.

    + <#else> + + + + + + + + + <#list errors as error> + + + + + + +
    Numéro de commandeDate de commande
    ${error.platformOrderNumber}${error.orderTime?datetime?string('dd-MM-yyyy')}
    + + <#if skipped??> + + + + + + + + + <#list skipped as error> + + + + + + +
    Numéro de commandeDate de commande
    ${error.platformOrderNumber}${error.orderTime?datetime?string('dd-MM-yyyy')}
    + + + + Pour continuer à utiliser nos services, nous vous invitons à recharger votre compte. + + + Pour toute information complémentaire nous vous invitons à vous rapprocher de votre conseiller. + +<#include "../components/footer.ftl"> \ No newline at end of file diff --git a/jeecg-module-system/jeecg-system-biz/src/main/resources/templates/client/lowBalanceNotification.ftl b/jeecg-module-system/jeecg-system-biz/src/main/resources/templates/client/lowBalanceNotification.ftl new file mode 100644 index 000000000..d9fbd79ef --- /dev/null +++ b/jeecg-module-system/jeecg-system-biz/src/main/resources/templates/client/lowBalanceNotification.ftl @@ -0,0 +1,16 @@ +<#include "../components/header.ftl"> + + Cher(e) ${firstname} ${lastname}, + + + Vous recevez cet e-mail car votre solde sur la plateforme de WIA App est actuellement de ${balance} ${currency} + + <#if clientCategory != "vip"> + + Pour continuer à utiliser nos services, nous vous invitons à recharger votre compte. + + + + Pour toute information complémentaire nous vous invitons à vous rapprocher de votre conseiller. + +<#include "../components/footer.ftl"> \ No newline at end of file diff --git a/jeecg-module-system/jeecg-system-biz/src/main/resources/templates/components/footer.ftl b/jeecg-module-system/jeecg-system-biz/src/main/resources/templates/components/footer.ftl new file mode 100644 index 000000000..e7e1ba274 --- /dev/null +++ b/jeecg-module-system/jeecg-system-biz/src/main/resources/templates/components/footer.ftl @@ -0,0 +1,59 @@ + + Merci d’utiliser nos services. + + + Cordialement + + + L’équipe WIA Sourcing. + + + + + + + +<#-- --> +<#-- --> +<#-- --> +<#-- --> +<#-- --> +<#-- --> +<#-- --> +<#-- --> +<#--
    Nous contacterNotre site web
    --> + + + + + + + + + + + + +
    WIA SOURCING
    © 2018/2023 par WIA Sourcing Agency.
    TOUS DROITS RÉSERVÉS©
    + + + + + + + + +<#-- --> +<#-- --> +<#-- --> +<#-- --> +<#-- --> +<#-- --> + +
    Ce message a été envoyé automatiquement. Merci de ne pas y répondre.
    Ce message et ainsi que toutes les pièces jointes sont confidentielles.
    Si vous avez reçu ce message par erreur, merci de nous en avertir immédiatement et de détruire ce message.
    Service client :
    Pour obtenir plus d’informations concernant nos services, veuillez nous contacter à l’adresse ci-dessous ou en visitant notre site web.
    + + + + + + \ No newline at end of file diff --git a/jeecg-module-system/jeecg-system-biz/src/main/resources/templates/components/header.ftl b/jeecg-module-system/jeecg-system-biz/src/main/resources/templates/components/header.ftl new file mode 100644 index 000000000..21ca5b384 --- /dev/null +++ b/jeecg-module-system/jeecg-system-biz/src/main/resources/templates/components/header.ftl @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + +<#include "components/footer.ftl"> \ No newline at end of file diff --git a/jeecg-module-system/jeecg-system-biz/src/main/resources/templates/logisticChannelChoiceError.ftl b/jeecg-module-system/jeecg-system-biz/src/main/resources/templates/logisticChannelChoiceError.ftl index 722814778..9aeea51b3 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/resources/templates/logisticChannelChoiceError.ftl +++ b/jeecg-module-system/jeecg-system-biz/src/main/resources/templates/logisticChannelChoiceError.ftl @@ -1,113 +1,37 @@ - - - - - - -
    + + logo + +
    + + \ No newline at end of file diff --git a/jeecg-module-system/jeecg-system-biz/src/main/resources/templates/invoiceDetailMail.ftl b/jeecg-module-system/jeecg-system-biz/src/main/resources/templates/invoiceDetailMail.ftl index f0588d233..2e346cbfc 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/resources/templates/invoiceDetailMail.ftl +++ b/jeecg-module-system/jeecg-system-biz/src/main/resources/templates/invoiceDetailMail.ftl @@ -1,93 +1,17 @@ - - - - - - -
    - - - - - - - - - - - -
    - - logo - -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Cher Client(e),
    Vous trouverez en pièce-jointe le fichier que vous nous avez demandé :
    Type de fichier : ${fileType}
    Client : ${invoiceEntity}
    Numéro de facture : ${invoiceNumber}
    Merci d’utiliser nos services.
    Cordialement
    L’équipe WIA Sourcing.
    -
    - - - - - - - - - - - - - - - -
    Ce message a été envoyé automatiquement. Merci de ne pas répondre. Ce message et ainsi que toutes les pièces jointes sont confidentielles.
    Si vous avez reçu ce message par erreur, merci de nous avertir immédiatement et de détruire ce message.
    Service client :
    Pour obtenir plus d’informations concernant nos services, veuillez nous contacter à l’adresse ci-dessous ou en visitant notre site web.
    - - - - - - - - -
    Nous contacterNotre site web
    - - - - - - - - - - - - -
    WIA SOURCING
    © 2018/2023 par WIA Sourcing Agency.
    TOUS DROITS RÉSERVÉS©
    -
    - -" \ No newline at end of file +<#include "components/header.ftl"> +
    Cher Client(e),
    Vous trouverez en pièce-jointe le fichier que vous nous avez demandé :
    Type de fichier : ${fileType}
    Client : ${invoiceEntity}
    Numéro de facture : ${invoiceNumber}
    - +<#include "components/header.ftl"> + + + + + + + + + + +
    Cher(s) collègue(s),
    Des erreurs se sont produites lors de l'attribution d'une ligne de transport à une ou plusieurs commandes :
    Erreurs : + <#if errors?size = 0> + No error + +
    + - - - - - - - - - - - - - - -
    - - logo - -
    - - - - - - - - - - - - -
    Cher(s) collègue(s),
    Des erreurs se sont produites lors de l'attribution d'une ligne de transport à une ou plusieurs commandes :
    Erreurs : - <#if errors?size = 0> - No error - -
    - - - - - - - - - - <#list errors as error> - - - - - - - - -
    ShopOrder IDCountrySensitive Attribute
    ${error.shop}${error.orderId}${error.country}${error.sensitiveAttribute}
    -
    Merci d’utiliser nos services.
    Cordialement
    L’équipe WIA Sourcing.
    - - - - - - - - - - - - - - - - - - - -
    Ce message a été envoyé automatiquement. Merci de ne pas répondre. Ce message et ainsi que toutes les pièces jointes sont confidentielles.
    Si vous avez reçu ce message par erreur, merci de nous avertir immédiatement et de détruire ce message.
    Service client :
    Pour obtenir plus d’informations concernant nos services, veuillez nous contacter à l’adresse ci-dessous ou en visitant notre site web.
    - - - - - - - - -
    Nous contacterNotre site web
    - - - - - - - - - - - - -
    WIA SOURCING
    © 2018/2023 par WIA Sourcing Agency.
    TOUS DROITS RÉSERVÉS©
    - + Shop + Order ID + Country + Sensitive Attribute + + + <#list errors as error> + + ${error.shop} + ${error.orderId} + ${error.country} + ${error.sensitiveAttribute} + + - - \ No newline at end of file + +<#include "components/footer.ftl"> \ No newline at end of file diff --git a/jeecg-module-system/jeecg-system-biz/src/main/resources/templates/vipInvoicingJobReport.ftl b/jeecg-module-system/jeecg-system-biz/src/main/resources/templates/vipInvoicingJobReport.ftl index 728917954..782e58de1 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/resources/templates/vipInvoicingJobReport.ftl +++ b/jeecg-module-system/jeecg-system-biz/src/main/resources/templates/vipInvoicingJobReport.ftl @@ -1,109 +1,33 @@ - - - - - - - +<#include "components/header.ftl"> + + + + + + + + + + +
    Cher(s) collègue(s),
    Des erreurs se sont produites lors du déroulement de la tâche plannifiée suivante :
    ${job} invoicing job
    Erreurs : + <#if errors?size = 0> + No error + +
    + + + + + + + <#list errors as error> - - - - - - - - - - - - - - -
    ClientError Message
    - - logo - -
    - - - - - - - - - - - - -
    Cher(s) collègue(s),
    Des erreurs se sont produites lors du déroulement de la tâche plannifiée : VIP invoicing job
    Erreurs : - <#if errors?size = 0> - No error - -
    - - - - - - - - <#list errors as error> - - - - - - -
    ClientError Message
    ${error.internalCode}${error.errorMsg}
    -
    Merci d’utiliser nos services.
    Cordialement
    L’équipe WIA Sourcing.
    - - - - - - - - - - - - - - - - - - - -
    Ce message a été envoyé automatiquement. Merci de ne pas répondre. Ce message et ainsi que toutes les pièces jointes sont confidentielles.
    Si vous avez reçu ce message par erreur, merci de nous avertir immédiatement et de détruire ce message.
    Service client :
    Pour obtenir plus d’informations concernant nos services, veuillez nous contacter à l’adresse ci-dessous ou en visitant notre site web.
    - - - - - - - - -
    Nous contacterNotre site web
    - - - - - - - - - - - - -
    WIA SOURCING
    © 2018/2023 par WIA Sourcing Agency.
    TOUS DROITS RÉSERVÉS©
    - + ${error.internalCode} + ${error.errorMsg} + - - \ No newline at end of file + +<#include "components/footer.ftl"> \ No newline at end of file