mirror of https://github.com/jeecgboot/jeecg-boot
feature : confirmed clients invoicing job
parent
6978554075
commit
b718a23b9c
|
|
@ -13,6 +13,7 @@ import org.jeecg.common.aspect.annotation.AutoLog;
|
||||||
import org.jeecg.common.system.query.QueryGenerator;
|
import org.jeecg.common.system.query.QueryGenerator;
|
||||||
import org.jeecg.common.system.vo.LoginUser;
|
import org.jeecg.common.system.vo.LoginUser;
|
||||||
import org.jeecg.common.util.oConvertUtils;
|
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.domain.purchase.invoice.InvoiceData;
|
||||||
import org.jeecg.modules.business.entity.*;
|
import org.jeecg.modules.business.entity.*;
|
||||||
import org.jeecg.modules.business.service.*;
|
import org.jeecg.modules.business.service.*;
|
||||||
|
|
@ -421,7 +422,7 @@ public class PurchaseOrderController {
|
||||||
*/
|
*/
|
||||||
@AutoLog(value = "商品采购清单-通过客户id查询")
|
@AutoLog(value = "商品采购清单-通过客户id查询")
|
||||||
@RequestMapping(value = "/admin/loadInventory")
|
@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);
|
Client client = clientService.getById(clientId);
|
||||||
ClientInfo clientInfo = new ClientInfo(client);
|
ClientInfo clientInfo = new ClientInfo(client);
|
||||||
List<ImportedInventory> importedInventories = importedInventoryService.selectByClientId(clientId);
|
List<ImportedInventory> importedInventories = importedInventoryService.selectByClientId(clientId);
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,8 @@ public class UserClientController {
|
||||||
public Result<?> getClientByUserId() {
|
public Result<?> getClientByUserId() {
|
||||||
LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
|
LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
|
||||||
String userId = loginUser.getId();
|
String userId = loginUser.getId();
|
||||||
userId = "1708866308713140225";
|
// userId = "1708866308713140225"; //EP
|
||||||
|
// userId = "1721929497801580546"; //ND
|
||||||
Client client = userClientService.getClientByUserId(userId);
|
Client client = userClientService.getClientByUserId(userId);
|
||||||
if(client == null) {
|
if(client == null) {
|
||||||
List<SysRole> sysRoles = sysUserRoleService.getUserRole(userId);
|
List<SysRole> sysRoles = sysUserRoleService.getUserRole(userId);
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@ import org.springframework.web.bind.annotation.*;
|
||||||
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;
|
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;
|
||||||
|
|
||||||
import javax.mail.Authenticator;
|
import javax.mail.Authenticator;
|
||||||
|
import javax.mail.MessagingException;
|
||||||
import javax.mail.PasswordAuthentication;
|
import javax.mail.PasswordAuthentication;
|
||||||
import javax.mail.Session;
|
import javax.mail.Session;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
@ -235,6 +236,8 @@ public class InvoiceController {
|
||||||
} catch (IOException | ParseException e) {
|
} catch (IOException | ParseException e) {
|
||||||
log.error(e.getMessage());
|
log.error(e.getMessage());
|
||||||
return Result.error("Sorry, server error, please try later");
|
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) {
|
} catch (IOException | ParseException e) {
|
||||||
log.error(e.getMessage());
|
log.error(e.getMessage());
|
||||||
return Result.error("Sorry, server error, please try later");
|
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());
|
clientId = clientIDCodeMap.get(estimation.getCode());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
clientId = clientService.getClientByInternalCode(estimation.getCode());
|
clientId = clientService.getClientIdByCode(estimation.getCode());
|
||||||
clientIDCodeMap.put(estimation.getCode(), clientId);
|
clientIDCodeMap.put(estimation.getCode(), clientId);
|
||||||
}
|
}
|
||||||
if (estimation.getIsCompleteInvoice().equals("1")) {
|
if (estimation.getIsCompleteInvoice().equals("1")) {
|
||||||
|
|
@ -453,7 +458,7 @@ public class InvoiceController {
|
||||||
});
|
});
|
||||||
for(Map.Entry<String, List<ShippingFeesEstimation>> entry : estimationClientMap.entrySet()) {
|
for(Map.Entry<String, List<ShippingFeesEstimation>> entry : estimationClientMap.entrySet()) {
|
||||||
String code = entry.getKey();
|
String code = entry.getKey();
|
||||||
String clientId = clientService.getClientByInternalCode(code);
|
String clientId = clientService.getClientIdByCode(code);
|
||||||
List<String> shops = new ArrayList<>();
|
List<String> shops = new ArrayList<>();
|
||||||
int ordersToProcess = 0;
|
int ordersToProcess = 0;
|
||||||
int processedOrders = 0;
|
int processedOrders = 0;
|
||||||
|
|
|
||||||
|
|
@ -75,6 +75,8 @@ public class ShippingInvoiceController {
|
||||||
@Autowired
|
@Autowired
|
||||||
private IPlatformOrderService platformOrderService;
|
private IPlatformOrderService platformOrderService;
|
||||||
@Autowired
|
@Autowired
|
||||||
|
private IPurchaseOrderService purchaseOrderService;
|
||||||
|
@Autowired
|
||||||
private ISavRefundService savRefundService;
|
private ISavRefundService savRefundService;
|
||||||
@Autowired
|
@Autowired
|
||||||
private IShippingInvoiceService shippingInvoiceService;
|
private IShippingInvoiceService shippingInvoiceService;
|
||||||
|
|
@ -510,6 +512,7 @@ public class ShippingInvoiceController {
|
||||||
log.info("Cancelling invoice number : {}", invoiceNumber);
|
log.info("Cancelling invoice number : {}", invoiceNumber);
|
||||||
platformOrderContentService.cancelInvoice(invoiceNumber);
|
platformOrderContentService.cancelInvoice(invoiceNumber);
|
||||||
platformOrderService.cancelInvoice(invoiceNumber);
|
platformOrderService.cancelInvoice(invoiceNumber);
|
||||||
|
purchaseOrderService.cancelInvoice(invoiceNumber);
|
||||||
savRefundService.cancelInvoice(invoiceNumber);
|
savRefundService.cancelInvoice(invoiceNumber);
|
||||||
shippingInvoiceService.delMain(id);
|
shippingInvoiceService.delMain(id);
|
||||||
log.info("Updating balance ...");
|
log.info("Updating balance ...");
|
||||||
|
|
@ -571,6 +574,7 @@ public class ShippingInvoiceController {
|
||||||
public Result<?> cancelBatchInvoice(@RequestParam("ids") List<String> ids, @RequestParam("invoiceNumbers") List<String> invoiceNumbers, @RequestParam("clientIds") List<String> clientIds) {
|
public Result<?> cancelBatchInvoice(@RequestParam("ids") List<String> ids, @RequestParam("invoiceNumbers") List<String> invoiceNumbers, @RequestParam("clientIds") List<String> clientIds) {
|
||||||
|
|
||||||
log.info("Cancelling invoices : {}", invoiceNumbers);
|
log.info("Cancelling invoices : {}", invoiceNumbers);
|
||||||
|
purchaseOrderService.cancelBatchInvoice(invoiceNumbers);
|
||||||
platformOrderContentService.cancelBatchInvoice(invoiceNumbers);
|
platformOrderContentService.cancelBatchInvoice(invoiceNumbers);
|
||||||
platformOrderService.cancelBatchInvoice(invoiceNumbers);
|
platformOrderService.cancelBatchInvoice(invoiceNumbers);
|
||||||
savRefundService.cancelBatchInvoice(invoiceNumbers);
|
savRefundService.cancelBatchInvoice(invoiceNumbers);
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ import org.jeecg.common.aspect.annotation.AutoLog;
|
||||||
import org.jeecg.common.system.query.QueryGenerator;
|
import org.jeecg.common.system.query.QueryGenerator;
|
||||||
import org.jeecg.common.system.vo.LoginUser;
|
import org.jeecg.common.system.vo.LoginUser;
|
||||||
import org.jeecg.common.util.oConvertUtils;
|
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.ClientPlatformOrderContent;
|
||||||
import org.jeecg.modules.business.entity.PlatformOrder;
|
import org.jeecg.modules.business.entity.PlatformOrder;
|
||||||
import org.jeecg.modules.business.entity.PlatformOrderContent;
|
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."
|
notes = "Compute order statistic data of platform orders indicated by its identifier."
|
||||||
)
|
)
|
||||||
@PostMapping(value = "/computeInfo", consumes = "application/json", produces = "application/json")
|
@PostMapping(value = "/computeInfo", consumes = "application/json", produces = "application/json")
|
||||||
public Result<OrdersStatisticData> queryOrdersStatisticInfo(@RequestBody List<String> orderIds) {
|
public Result<OrdersStatisticData> queryOrdersStatisticInfo(@RequestBody List<String> orderIds) throws UserException {
|
||||||
log.info("Calculating statistic information for orders: {}", orderIds);
|
log.info("Calculating statistic information for orders: {}", orderIds);
|
||||||
OrdersStatisticData ordersData = platformOrderService.getPlatformOrdersStatisticData(orderIds);
|
OrdersStatisticData ordersData = platformOrderService.getPlatformOrdersStatisticData(orderIds);
|
||||||
log.info("Got statistic information: {}", ordersData);
|
log.info("Got statistic information: {}", ordersData);
|
||||||
|
|
@ -212,7 +213,7 @@ public class ClientPlatformOrderController {
|
||||||
"client confirm information."
|
"client confirm information."
|
||||||
)
|
)
|
||||||
@PostMapping(value = "/placeOrder", consumes = "application/json", produces = "application/json")
|
@PostMapping(value = "/placeOrder", consumes = "application/json", produces = "application/json")
|
||||||
public Result<PurchaseConfirmation> placeOrder(@RequestBody List<String> orderIds) {
|
public Result<PurchaseConfirmation> placeOrder(@RequestBody List<String> orderIds) throws UserException {
|
||||||
log.info("One client place a purchase order");
|
log.info("One client place a purchase order");
|
||||||
PurchaseConfirmation d = platformOrderService.confirmPurchaseByPlatformOrder(orderIds);
|
PurchaseConfirmation d = platformOrderService.confirmPurchaseByPlatformOrder(orderIds);
|
||||||
log.info(d.toString());
|
log.info(d.toString());
|
||||||
|
|
@ -226,7 +227,7 @@ public class ClientPlatformOrderController {
|
||||||
* @return confirmation.
|
* @return confirmation.
|
||||||
*/
|
*/
|
||||||
@PostMapping(value = "/adjustOrder", consumes = "application/json", produces = "application/json")
|
@PostMapping(value = "/adjustOrder", consumes = "application/json", produces = "application/json")
|
||||||
public Result<PurchaseConfirmation> adjustOrder(@RequestBody List<SkuQuantity> skuQuantities) {
|
public Result<PurchaseConfirmation> adjustOrder(@RequestBody List<SkuQuantity> skuQuantities) throws UserException {
|
||||||
log.info("One client adjust its purchase order");
|
log.info("One client adjust its purchase order");
|
||||||
log.info("Content: {}", skuQuantities);
|
log.info("Content: {}", skuQuantities);
|
||||||
PurchaseConfirmation d = platformOrderService.confirmPurchaseBySkuQuantity(skuQuantities);
|
PurchaseConfirmation d = platformOrderService.confirmPurchaseBySkuQuantity(skuQuantities);
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import io.swagger.annotations.ApiOperation;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.jeecg.common.api.vo.Result;
|
import org.jeecg.common.api.vo.Result;
|
||||||
import org.jeecg.common.aspect.annotation.AutoLog;
|
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.controller.client.requestParams.PurchaseRequest;
|
||||||
import org.jeecg.modules.business.entity.PurchaseOrder;
|
import org.jeecg.modules.business.entity.PurchaseOrder;
|
||||||
import org.jeecg.modules.business.service.IPurchaseOrderService;
|
import org.jeecg.modules.business.service.IPurchaseOrderService;
|
||||||
|
|
@ -64,7 +65,7 @@ public class ClientPurchaseController {
|
||||||
@AutoLog(value = "商品采购订单-添加")
|
@AutoLog(value = "商品采购订单-添加")
|
||||||
@ApiOperation(value = "商品采购订单-添加", notes = "商品采购订单-添加")
|
@ApiOperation(value = "商品采购订单-添加", notes = "商品采购订单-添加")
|
||||||
@PostMapping(value = "/add")
|
@PostMapping(value = "/add")
|
||||||
public Result<String> addPurchaseOrder(@RequestBody PurchaseRequest purchaseRequest) {
|
public Result<String> addPurchaseOrder(@RequestBody PurchaseRequest purchaseRequest) throws UserException {
|
||||||
String id = purchaseOrderService.addPurchase(
|
String id = purchaseOrderService.addPurchase(
|
||||||
purchaseRequest.getSkuQuantity(),
|
purchaseRequest.getSkuQuantity(),
|
||||||
purchaseRequest.getPlatformOrderIDList()
|
purchaseRequest.getPlatformOrderIDList()
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,9 @@ package org.jeecg.modules.business.controller.client;
|
||||||
import cn.hutool.core.date.DateTime;
|
import cn.hutool.core.date.DateTime;
|
||||||
import io.swagger.annotations.Api;
|
import io.swagger.annotations.Api;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.jeecg.common.api.dto.message.TemplateMessageDTO;
|
||||||
import org.jeecg.common.api.vo.Result;
|
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.domain.shippingInvoice.ShippingInvoiceFactory;
|
||||||
import org.jeecg.modules.business.entity.PlatformOrder;
|
import org.jeecg.modules.business.entity.PlatformOrder;
|
||||||
import org.jeecg.modules.business.entity.PlatformOrderContent;
|
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.Estimation;
|
||||||
import org.jeecg.modules.business.vo.ShippingFeesEstimation;
|
import org.jeecg.modules.business.vo.ShippingFeesEstimation;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
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.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
|
@ -28,6 +31,8 @@ import java.util.stream.Collectors;
|
||||||
@RequestMapping("/transaction")
|
@RequestMapping("/transaction")
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class TransactionController {
|
public class TransactionController {
|
||||||
|
@Autowired
|
||||||
|
private EmailService emailService;
|
||||||
@Autowired
|
@Autowired
|
||||||
private TransactionMapper transactionMapper;
|
private TransactionMapper transactionMapper;
|
||||||
@Autowired
|
@Autowired
|
||||||
|
|
@ -68,6 +73,13 @@ public class TransactionController {
|
||||||
ISavRefundWithDetailService savRefundWithDetailService;
|
ISavRefundWithDetailService savRefundWithDetailService;
|
||||||
@Autowired
|
@Autowired
|
||||||
ISavRefundService savRefundService;
|
ISavRefundService savRefundService;
|
||||||
|
@Autowired
|
||||||
|
private ISysBaseAPI ISysBaseApi;
|
||||||
|
@Autowired
|
||||||
|
Environment env;
|
||||||
|
|
||||||
|
private final String SECTION_START = "<section><ul>";
|
||||||
|
private final String SECTION_END = "</ul></section>";
|
||||||
@GetMapping(value="/list")
|
@GetMapping(value="/list")
|
||||||
public Result<?> list() {
|
public Result<?> list() {
|
||||||
return Result.ok(transactionMapper.list());
|
return Result.ok(transactionMapper.list());
|
||||||
|
|
@ -91,7 +103,7 @@ public class TransactionController {
|
||||||
ShippingInvoiceFactory factory = new ShippingInvoiceFactory(
|
ShippingInvoiceFactory factory = new ShippingInvoiceFactory(
|
||||||
platformOrderService, clientMapper, shopMapper, logisticChannelMapper, logisticChannelPriceMapper,
|
platformOrderService, clientMapper, shopMapper, logisticChannelMapper, logisticChannelPriceMapper,
|
||||||
platformOrderContentService, skuDeclaredValueService, countryService, exchangeRatesMapper,
|
platformOrderContentService, skuDeclaredValueService, countryService, exchangeRatesMapper,
|
||||||
purchaseOrderService, purchaseOrderContentMapper, skuPromotionHistoryMapper, savRefundService, savRefundWithDetailService);
|
purchaseOrderService, purchaseOrderContentMapper, skuPromotionHistoryMapper, savRefundService, savRefundWithDetailService, emailService, env);
|
||||||
List<ShippingFeesEstimation> shippingFeesEstimations = factory.getEstimations(clientId, orderIds, errorMessages);
|
List<ShippingFeesEstimation> shippingFeesEstimations = factory.getEstimations(clientId, orderIds, errorMessages);
|
||||||
if(shippingFeesEstimations.isEmpty())
|
if(shippingFeesEstimations.isEmpty())
|
||||||
return Result.OK("No estimation found.");
|
return Result.OK("No estimation found.");
|
||||||
|
|
@ -131,6 +143,28 @@ public class TransactionController {
|
||||||
System.out.println("Purchase Fee " + currency + " : " + purchaseEstimation);
|
System.out.println("Purchase Fee " + currency + " : " + purchaseEstimation);
|
||||||
System.out.println("Shipping Fee " + currency + " : " + shippingFeesEstimation);
|
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("<li>" + i + " : " + errorMessages.get(i-1) +"</li>");
|
||||||
|
if(i%max_entries==0 || i == errorMessages.size()) {
|
||||||
|
errors = errors.concat(SECTION_END);
|
||||||
|
Map<String, String> 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));
|
return Result.ok(new Estimation(shippingFeesEstimation, purchaseEstimation, currency, errorMessages, shopIds, new DateTime(startDate).toString(), new DateTime(endDate).toString(), isCompleteInvoiceReady));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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<Client> confirmedClients = clientService.getClientsByType("confirmed");
|
||||||
|
List<Client> clients = new ArrayList<>();
|
||||||
|
List<BalanceData> balanceDataList = new ArrayList<>();
|
||||||
|
List<BalanceData> shippingBalanceDataList = new ArrayList<>();
|
||||||
|
List<BalanceData> 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<InvoiceMetaData> 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<InvoiceMetaData> metaDataErrorList = new ArrayList<>();
|
||||||
|
List<InvoiceMetaData> 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<FactureDetail> factureDetails = platformOrderShippingInvoiceService.getInvoiceDetail(metaData.getInvoiceCode());
|
||||||
|
List<SavRefundWithDetail> 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<String, Object> 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<BalanceData> 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<String, Object> 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.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,9 +2,9 @@ package org.jeecg.modules.business.domain.job;
|
||||||
|
|
||||||
import freemarker.template.Template;
|
import freemarker.template.Template;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang3.tuple.Pair;
|
|
||||||
import org.jeecg.modules.business.entity.*;
|
import org.jeecg.modules.business.entity.*;
|
||||||
import org.jeecg.modules.business.service.*;
|
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.FactureDetail;
|
||||||
import org.jeecg.modules.business.vo.InvoiceMetaData;
|
import org.jeecg.modules.business.vo.InvoiceMetaData;
|
||||||
import org.quartz.Job;
|
import org.quartz.Job;
|
||||||
|
|
@ -19,12 +19,15 @@ import javax.mail.Authenticator;
|
||||||
import javax.mail.PasswordAuthentication;
|
import javax.mail.PasswordAuthentication;
|
||||||
import javax.mail.Session;
|
import javax.mail.Session;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.math.BigDecimal;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class VipInvoicingJob implements Job {
|
public class VipInvoicingJob implements Job {
|
||||||
|
@Autowired
|
||||||
|
private IBalanceService balanceService;
|
||||||
@Autowired
|
@Autowired
|
||||||
private IClientService clientService;
|
private IClientService clientService;
|
||||||
@Autowired
|
@Autowired
|
||||||
|
|
@ -40,7 +43,7 @@ public class VipInvoicingJob implements Job {
|
||||||
private FreeMarkerConfigurer freemarkerConfigurer;
|
private FreeMarkerConfigurer freemarkerConfigurer;
|
||||||
@Override
|
@Override
|
||||||
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
|
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
|
||||||
log.info("VIP Invoicing Job executed.");
|
log.info("VIP Invoicing Job started ...");
|
||||||
List<Client> clients = clientService.getClientsByType("vip");
|
List<Client> clients = clientService.getClientsByType("vip");
|
||||||
List<String> shippingClientIds = clients.stream().filter(client -> client.getIsCompleteInvoice().equals("0")).map(Client::getId).collect(Collectors.toList());
|
List<String> shippingClientIds = clients.stream().filter(client -> client.getIsCompleteInvoice().equals("0")).map(Client::getId).collect(Collectors.toList());
|
||||||
List<String> completeClientIds = clients.stream().filter(client -> client.getIsCompleteInvoice().equals("1")).map(Client::getId).collect(Collectors.toList());
|
List<String> 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<InvoiceMetaData> metaDataErrorList = new ArrayList<>();
|
List<InvoiceMetaData> metaDataErrorList = new ArrayList<>();
|
||||||
|
List<InvoiceMetaData> invoicedMetaDataList = new ArrayList<>(); // list of invoice meta data that has been invoiced
|
||||||
log.info("Generating detail files ...0/{}", invoiceList.size());
|
log.info("Generating detail files ...0/{}", invoiceList.size());
|
||||||
int cpt = 1;
|
int cpt = 1;
|
||||||
for(InvoiceMetaData metaData: invoiceList){
|
for(InvoiceMetaData metaData: invoiceList){
|
||||||
|
|
@ -69,6 +73,7 @@ public class VipInvoicingJob implements Job {
|
||||||
metaDataErrorList.add(metaData);
|
metaDataErrorList.add(metaData);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
invoicedMetaDataList.add(metaData);
|
||||||
List<FactureDetail> factureDetails = platformOrderShippingInvoiceService.getInvoiceDetail(metaData.getInvoiceCode());
|
List<FactureDetail> factureDetails = platformOrderShippingInvoiceService.getInvoiceDetail(metaData.getInvoiceCode());
|
||||||
List<SavRefundWithDetail> refunds = savRefundWithDetailService.getRefundsByInvoiceNumber(metaData.getInvoiceCode());
|
List<SavRefundWithDetail> refunds = savRefundWithDetailService.getRefundsByInvoiceNumber(metaData.getInvoiceCode());
|
||||||
try {
|
try {
|
||||||
|
|
@ -84,6 +89,7 @@ public class VipInvoicingJob implements Job {
|
||||||
String destEmail = env.getProperty("spring.mail.username");
|
String destEmail = env.getProperty("spring.mail.username");
|
||||||
Properties prop = emailService.getMailSender();
|
Properties prop = emailService.getMailSender();
|
||||||
Map<String, Object> templateModel = new HashMap<>();
|
Map<String, Object> templateModel = new HashMap<>();
|
||||||
|
templateModel.put("job", "VIP");
|
||||||
templateModel.put("errors", metaDataErrorList);
|
templateModel.put("errors", metaDataErrorList);
|
||||||
|
|
||||||
Session session = Session.getInstance(prop, new Authenticator() {
|
Session session = Session.getInstance(prop, new Authenticator() {
|
||||||
|
|
@ -104,6 +110,43 @@ public class VipInvoicingJob implements Job {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// emailing for low balance clients
|
||||||
|
List<BalanceData> 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<String, Object> 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.");
|
log.info("VIP invoicing job finished.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import com.google.common.cache.CacheBuilder;
|
||||||
import com.google.common.cache.CacheLoader;
|
import com.google.common.cache.CacheLoader;
|
||||||
import com.google.common.cache.LoadingCache;
|
import com.google.common.cache.LoadingCache;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.catalina.User;
|
||||||
import org.apache.commons.lang3.tuple.Pair;
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
import org.jeecg.modules.business.controller.UserException;
|
import org.jeecg.modules.business.controller.UserException;
|
||||||
import org.jeecg.modules.business.domain.codeGeneration.CompleteInvoiceCodeRule;
|
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.ShippingFeesEstimation;
|
||||||
import org.jeecg.modules.business.vo.SkuQuantity;
|
import org.jeecg.modules.business.vo.SkuQuantity;
|
||||||
import org.jeecg.modules.business.vo.SkuWeightDiscountServiceFees;
|
import org.jeecg.modules.business.vo.SkuWeightDiscountServiceFees;
|
||||||
|
import org.jeecg.modules.business.vo.clientPlatformOrder.section.OrdersStatisticData;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.springframework.beans.BeanUtils;
|
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.dao.IncorrectResultSizeDataAccessException;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import javax.mail.MessagingException;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.math.RoundingMode;
|
import java.math.RoundingMode;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.time.LocalDate;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
@ -51,6 +57,8 @@ public class ShippingInvoiceFactory {
|
||||||
private final SkuPromotionHistoryMapper skuPromotionHistoryMapper;
|
private final SkuPromotionHistoryMapper skuPromotionHistoryMapper;
|
||||||
private final ISavRefundService savRefundService;
|
private final ISavRefundService savRefundService;
|
||||||
private final ISavRefundWithDetailService savRefundWithDetailService;
|
private final ISavRefundWithDetailService savRefundWithDetailService;
|
||||||
|
private final EmailService emailService;
|
||||||
|
private final Environment env;
|
||||||
|
|
||||||
private final SimpleDateFormat SUBJECT_FORMAT = new SimpleDateFormat("yyyy-MM-dd");
|
private final SimpleDateFormat SUBJECT_FORMAT = new SimpleDateFormat("yyyy-MM-dd");
|
||||||
|
|
||||||
|
|
@ -78,7 +86,7 @@ public class ShippingInvoiceFactory {
|
||||||
ExchangeRatesMapper exchangeRatesMapper, IPurchaseOrderService purchaseOrderService,
|
ExchangeRatesMapper exchangeRatesMapper, IPurchaseOrderService purchaseOrderService,
|
||||||
PurchaseOrderContentMapper purchaseOrderContentMapper,
|
PurchaseOrderContentMapper purchaseOrderContentMapper,
|
||||||
SkuPromotionHistoryMapper skuPromotionHistoryMapper, ISavRefundService savRefundService,
|
SkuPromotionHistoryMapper skuPromotionHistoryMapper, ISavRefundService savRefundService,
|
||||||
ISavRefundWithDetailService savRefundWithDetailService) {
|
ISavRefundWithDetailService savRefundWithDetailService, EmailService emailService, Environment env) {
|
||||||
this.platformOrderService = platformOrderService;
|
this.platformOrderService = platformOrderService;
|
||||||
this.clientMapper = clientMapper;
|
this.clientMapper = clientMapper;
|
||||||
this.shopMapper = shopMapper;
|
this.shopMapper = shopMapper;
|
||||||
|
|
@ -93,6 +101,8 @@ public class ShippingInvoiceFactory {
|
||||||
this.skuPromotionHistoryMapper = skuPromotionHistoryMapper;
|
this.skuPromotionHistoryMapper = skuPromotionHistoryMapper;
|
||||||
this.savRefundService = savRefundService;
|
this.savRefundService = savRefundService;
|
||||||
this.savRefundWithDetailService = savRefundWithDetailService;
|
this.savRefundWithDetailService = savRefundWithDetailService;
|
||||||
|
this.emailService = emailService;
|
||||||
|
this.env = env;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -160,7 +170,7 @@ public class ShippingInvoiceFactory {
|
||||||
* channel price, this exception will be thrown.
|
* channel price, this exception will be thrown.
|
||||||
*/
|
*/
|
||||||
@Transactional
|
@Transactional
|
||||||
public CompleteInvoice createCompleteShippingInvoice(String username, String customerId, List<String> orderIds, String shippingMethod, String start, String end) throws UserException {
|
public CompleteInvoice createCompleteShippingInvoice(String username, String customerId, BigDecimal balance, List<String> orderIds, String shippingMethod, String start, String end) throws UserException, MessagingException {
|
||||||
log.info("Creating a complete invoice for \n client ID: {}, order IDs: {}]", customerId, orderIds);
|
log.info("Creating a complete invoice for \n client ID: {}, order IDs: {}]", customerId, orderIds);
|
||||||
// find orders and their contents of the invoice
|
// find orders and their contents of the invoice
|
||||||
Map<PlatformOrder, List<PlatformOrderContent>> uninvoicedOrderToContent = platformOrderService.fetchOrderData(orderIds);
|
Map<PlatformOrder, List<PlatformOrderContent>> uninvoicedOrderToContent = platformOrderService.fetchOrderData(orderIds);
|
||||||
|
|
@ -181,8 +191,9 @@ public class ShippingInvoiceFactory {
|
||||||
else if(shippingMethod.equals("all"))
|
else if(shippingMethod.equals("all"))
|
||||||
subject = String.format("Purchase and Shipping fees, order time from %s to %s", start, end);
|
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");
|
else throw new UserException("Couldn't create complete invoice for unknown shipping method");
|
||||||
|
if(balance != null)
|
||||||
return createInvoice(username, customerId, shopIds, uninvoicedOrderToContent, savRefunds, subject);
|
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.
|
* channel price, this exception will be thrown.
|
||||||
*/
|
*/
|
||||||
@Transactional
|
@Transactional
|
||||||
public CompleteInvoice createInvoice(String username, String customerId, List<String> shopIds,
|
public CompleteInvoice createInvoice(String username, String customerId, BigDecimal balance, List<String> shopIds,
|
||||||
Map<PlatformOrder, List<PlatformOrderContent>> orderAndContent,
|
Map<PlatformOrder, List<PlatformOrderContent>> orderAndContent,
|
||||||
List<SavRefundWithDetail> savRefunds, String subject) throws UserException {
|
List<SavRefundWithDetail> savRefunds, String subject) throws UserException {
|
||||||
Client client = clientMapper.selectById(customerId);
|
Client client = clientMapper.selectById(customerId);
|
||||||
|
|
@ -235,10 +246,145 @@ public class ShippingInvoiceFactory {
|
||||||
shops.forEach(shop -> shopPackageMatFeeMap.put(shop.getId(), shop.getPackagingMaterialFee()));
|
shops.forEach(shop -> shopPackageMatFeeMap.put(shop.getId(), shop.getPackagingMaterialFee()));
|
||||||
String invoiceCode = generateCompleteInvoiceCode();
|
String invoiceCode = generateCompleteInvoiceCode();
|
||||||
log.info("New invoice code: {}", invoiceCode);
|
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);
|
latestDeclaredValues, client, shopServiceFeeMap, shopPackageMatFeeMap, invoiceCode);
|
||||||
BigDecimal eurToUsd = exchangeRatesMapper.getLatestExchangeRate("EUR", "USD");
|
BigDecimal eurToUsd = exchangeRatesMapper.getLatestExchangeRate("EUR", "USD");
|
||||||
|
List<String> orderIds = orderAndContent.keySet().stream().map(PlatformOrder::getId).collect(toList());
|
||||||
|
List<SkuQuantity> skuQuantities = platformOrderContentService.searchOrderContent(orderIds);
|
||||||
|
|
||||||
|
String purchaseID = purchaseOrderService.addPurchase(username, client, invoiceCode, skuQuantities, orderAndContent);
|
||||||
|
|
||||||
|
List<PurchaseInvoiceEntry> purchaseOrderSkuList = purchaseOrderContentMapper.selectInvoiceDataByID(purchaseID);
|
||||||
|
List<PromotionDetail> 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.
|
||||||
|
* <p>
|
||||||
|
* To generate an invoice, it
|
||||||
|
* <ol>
|
||||||
|
* <li>Search orders and their contents based on shop and date range</li>
|
||||||
|
* <li>Generate a new invoice code</li>
|
||||||
|
* <li>Find proper logistic channel price for each order </li>
|
||||||
|
* <li>Update prices of orders and their contents</li>
|
||||||
|
* <li>Generate a invoice</li>
|
||||||
|
* <li>Update invoiced their orders and contents to DB</li>
|
||||||
|
* </ol>
|
||||||
|
*
|
||||||
|
* @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<String> shopIds,
|
||||||
|
Map<PlatformOrder, List<PlatformOrderContent>> orderAndContent,
|
||||||
|
List<SavRefundWithDetail> 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<String, List<String>> 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<String, BigDecimal> skuRealWeights = new HashMap<>();
|
||||||
|
Map<String, BigDecimal> skuServiceFees = new HashMap<>();
|
||||||
|
skuDataPreparation(skuRealWeights, skuServiceFees);
|
||||||
|
List<Country> countryList = countryService.findAll();
|
||||||
|
Map<String, LogisticChannel> logisticChannelMap = logisticChannelMapper.getAll().stream()
|
||||||
|
.collect(toMap(LogisticChannel::getId, Function.identity()));
|
||||||
|
Map<LogisticChannel, List<LogisticChannelPrice>> channelPriceMap = getChannelPriceMap(logisticChannelMap, orderAndContent, true);
|
||||||
|
List<SkuDeclaredValue> latestDeclaredValues = skuDeclaredValueService.getLatestDeclaredValues();
|
||||||
|
|
||||||
|
List<Shop> shops = shopMapper.selectBatchIds(shopIds);
|
||||||
|
Map<String, BigDecimal> shopServiceFeeMap = new HashMap<>();
|
||||||
|
Map<String, BigDecimal> 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<PlatformOrder, List<PlatformOrderContent>> 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<String, Object> 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<String, List<String>> 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<String> orderIds = orderAndContent.keySet().stream().map(PlatformOrder::getId).collect(toList());
|
List<String> orderIds = orderAndContent.keySet().stream().map(PlatformOrder::getId).collect(toList());
|
||||||
List<SkuQuantity> skuQuantities = platformOrderContentService.searchOrderContent(orderIds);
|
List<SkuQuantity> skuQuantities = platformOrderContentService.searchOrderContent(orderIds);
|
||||||
|
|
||||||
|
|
@ -328,7 +474,7 @@ public class ShippingInvoiceFactory {
|
||||||
* channel price, this exception will be thrown.
|
* channel price, this exception will be thrown.
|
||||||
*/
|
*/
|
||||||
@Transactional
|
@Transactional
|
||||||
public ShippingInvoice createInvoice(String customerId, List<String> shopIds, Date begin, Date end, List<Integer> erpStatuses, List<String> warehouses) throws UserException {
|
public ShippingInvoice createInvoice(String customerId, List<String> shopIds, Date begin, Date end, List<Integer> erpStatuses, List<String> warehouses, BigDecimal balance) throws UserException {
|
||||||
log.info(
|
log.info(
|
||||||
"Creating an invoice with arguments:\n client ID: {}, shop IDs: {}, period:[{} - {}]",
|
"Creating an invoice with arguments:\n client ID: {}, shop IDs: {}, period:[{} - {}]",
|
||||||
customerId, shopIds.toString(), begin, end
|
customerId, shopIds.toString(), begin, end
|
||||||
|
|
@ -345,7 +491,7 @@ public class ShippingInvoiceFactory {
|
||||||
);
|
);
|
||||||
uninvoicedOrderToContent = platformOrderService.findUninvoicedOrders(shopIds, begin, end, warehouses);
|
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(
|
subject = String.format(
|
||||||
"Pre-Shipping fees order time from %s to %s",
|
"Pre-Shipping fees order time from %s to %s",
|
||||||
SUBJECT_FORMAT.format(begin),
|
SUBJECT_FORMAT.format(begin),
|
||||||
|
|
@ -361,6 +507,9 @@ public class ShippingInvoiceFactory {
|
||||||
);
|
);
|
||||||
uninvoicedOrderToContent = platformOrderService.findUninvoicedOrderContentsForShopsAndStatus(shopIds, begin, end, erpStatuses, warehouses);
|
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);
|
return createInvoice(customerId, shopIds, uninvoicedOrderToContent, savRefunds, subject, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -419,7 +568,7 @@ public class ShippingInvoiceFactory {
|
||||||
shops.forEach(shop -> shopPackageMatFeeMap.put(shop.getId(), shop.getPackagingMaterialFee()));
|
shops.forEach(shop -> shopPackageMatFeeMap.put(shop.getId(), shop.getPackagingMaterialFee()));
|
||||||
String invoiceCode = generateInvoiceCode();
|
String invoiceCode = generateInvoiceCode();
|
||||||
log.info("New invoice code: {}", invoiceCode);
|
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);
|
latestDeclaredValues, client, shopServiceFeeMap, shopPackageMatFeeMap, invoiceCode);
|
||||||
BigDecimal eurToUsd = exchangeRatesMapper.getLatestExchangeRate("EUR", "USD");
|
BigDecimal eurToUsd = exchangeRatesMapper.getLatestExchangeRate("EUR", "USD");
|
||||||
if (savRefunds != null) {
|
if (savRefunds != null) {
|
||||||
|
|
@ -429,6 +578,80 @@ public class ShippingInvoiceFactory {
|
||||||
updateOrdersAndContentsInDb(orderAndContent);
|
updateOrdersAndContentsInDb(orderAndContent);
|
||||||
return invoice;
|
return invoice;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Creates an invoice based for a client, it's balance, a list of shops, a date range.
|
||||||
|
* <p>
|
||||||
|
* To generate an invoice, it
|
||||||
|
* <ol>
|
||||||
|
* <li>Search orders and their contents based on shop and date range</li>
|
||||||
|
* <li>Generate a new invoice code</li>
|
||||||
|
* <li>Find propre logistic channel price for each order </li>
|
||||||
|
* <li>Update prices of orders and their contents</li>
|
||||||
|
* <li>Generate a invoice</li>
|
||||||
|
* <li>Update invoiced their orders and contents to DB</li>
|
||||||
|
* </ol>
|
||||||
|
*
|
||||||
|
* @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<String> shopIds,
|
||||||
|
Map<PlatformOrder, List<PlatformOrderContent>> orderAndContent,
|
||||||
|
List<SavRefundWithDetail> 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<String, BigDecimal> skuRealWeights = new HashMap<>();
|
||||||
|
Map<String, BigDecimal> skuServiceFees = new HashMap<>();
|
||||||
|
skuDataPreparation(skuRealWeights, skuServiceFees);
|
||||||
|
List<Country> countryList = countryService.findAll();
|
||||||
|
Map<LogisticChannel, List<LogisticChannelPrice>> channelPriceMap;
|
||||||
|
Map<String, LogisticChannel> 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<SkuDeclaredValue> latestDeclaredValues = skuDeclaredValueService.getLatestDeclaredValues();
|
||||||
|
|
||||||
|
Client client = clientMapper.selectById(customerId);
|
||||||
|
List<Shop> shops = shopMapper.selectBatchIds(shopIds);
|
||||||
|
Map<String, BigDecimal> shopServiceFeeMap = new HashMap<>();
|
||||||
|
Map<String, BigDecimal> 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<String, List<String>> 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
|
* Construct a map between LogisticChannel and LogisticChannelPrices, by using distinct country names and
|
||||||
|
|
@ -484,7 +707,7 @@ public class ShippingInvoiceFactory {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<String, List<String>> calculateFees(Map<String, LogisticChannel> logisticChannelMap, Map<PlatformOrder, List<PlatformOrderContent>> orderAndContent,
|
private Map<String, List<String>> calculateFees(BigDecimal balance, Map<String, LogisticChannel> logisticChannelMap, Map<PlatformOrder, List<PlatformOrderContent>> orderAndContent,
|
||||||
Map<LogisticChannel, List<LogisticChannelPrice>> channelPriceMap,
|
Map<LogisticChannel, List<LogisticChannelPrice>> channelPriceMap,
|
||||||
List<Country> countryList,
|
List<Country> countryList,
|
||||||
Map<String, BigDecimal> skuRealWeights,
|
Map<String, BigDecimal> skuRealWeights,
|
||||||
|
|
@ -496,30 +719,45 @@ public class ShippingInvoiceFactory {
|
||||||
String invoiceCode
|
String invoiceCode
|
||||||
) throws UserException {
|
) throws UserException {
|
||||||
Map<String, List<String>> platformOrderIdsWithPb = new HashMap<>();
|
Map<String, List<String>> platformOrderIdsWithPb = new HashMap<>();
|
||||||
|
// Virtual balance is only used for client type 1 in invoicing job
|
||||||
|
BigDecimal virtualBalance = balance;
|
||||||
|
List<PlatformOrder> insufficientBalanceOrders = new ArrayList<>();
|
||||||
|
boolean skip = false;
|
||||||
|
Map<PlatformOrder, List<PlatformOrderContent>> 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
|
// find logistic channel price for each order based on its content
|
||||||
for (PlatformOrder uninvoicedOrder : orderAndContent.keySet()) {
|
for (PlatformOrder uninvoicedOrder : orderContentMap.keySet()) {
|
||||||
List<PlatformOrderContent> contents = orderAndContent.get(uninvoicedOrder);
|
if(skip) {
|
||||||
|
if(client.getInternalCode().equals("FT")) {
|
||||||
|
System.out.println("uninvoicedOrder order time : " + uninvoicedOrder.getOrderTime());
|
||||||
|
}
|
||||||
|
platformOrderIdsWithPb.put(uninvoicedOrder.getId(), Collections.singletonList("Skipped"));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
List<PlatformOrderContent> contents = orderContentMap.get(uninvoicedOrder);
|
||||||
if (contents.isEmpty()) {
|
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);
|
log.info("Calculating price for {} of order {}", contents, uninvoicedOrder);
|
||||||
Map<String, Integer> contentMap = new HashMap<>();
|
Map<String, Integer> contentSkuQtyMap = new HashMap<>();
|
||||||
for (PlatformOrderContent content : contents) {
|
for (PlatformOrderContent content : contents) {
|
||||||
String skuId = content.getSkuId();
|
String skuId = content.getSkuId();
|
||||||
if (contentMap.containsKey(skuId)) {
|
if (contentSkuQtyMap.containsKey(skuId)) {
|
||||||
contentMap.put(skuId, contentMap.get(skuId) + content.getQuantity());
|
contentSkuQtyMap.put(skuId, contentSkuQtyMap.get(skuId) + content.getQuantity());
|
||||||
} else {
|
} else {
|
||||||
contentMap.put(skuId, content.getQuantity());
|
contentSkuQtyMap.put(skuId, content.getQuantity());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// calculate weight of an order
|
// calculate weight of an order
|
||||||
Pair<BigDecimal, List<String>> contentWeightResult = platformOrderContentService.calculateWeight(
|
Pair<BigDecimal, List<String>> contentWeightResult = platformOrderContentService.calculateWeight(
|
||||||
contentMap,
|
contentSkuQtyMap,
|
||||||
skuRealWeights
|
skuRealWeights
|
||||||
);
|
);
|
||||||
if(!contentWeightResult.getValue().isEmpty()) {
|
if(!contentWeightResult.getValue().isEmpty()) {
|
||||||
platformOrderIdsWithPb.put(uninvoicedOrder.getPlatformOrderId(), contentWeightResult.getValue());
|
platformOrderIdsWithPb.put(uninvoicedOrder.getId(), contentWeightResult.getValue());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
BigDecimal contentWeight = contentWeightResult.getKey();
|
BigDecimal contentWeight = contentWeightResult.getKey();
|
||||||
|
|
@ -528,20 +766,16 @@ public class ShippingInvoiceFactory {
|
||||||
logisticChannelPair = findAppropriatePrice(countryList, logisticChannelMap,
|
logisticChannelPair = findAppropriatePrice(countryList, logisticChannelMap,
|
||||||
channelPriceMap, uninvoicedOrder, contentWeight);
|
channelPriceMap, uninvoicedOrder, contentWeight);
|
||||||
}
|
}
|
||||||
catch (UserException e) {
|
catch (RuntimeException | UserException e) {
|
||||||
platformOrderIdsWithPb.put(uninvoicedOrder.getPlatformOrderId(), Collections.singletonList(e.getMessage()));
|
platformOrderIdsWithPb.put(uninvoicedOrder.getId(), Collections.singletonList(e.getMessage()));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
LogisticChannelPrice price = logisticChannelPair.getRight();
|
LogisticChannelPrice price = logisticChannelPair.getRight();
|
||||||
// update attributes of orders and theirs content
|
|
||||||
BigDecimal packageMatFee = shopPackageMatFeeMap.get(uninvoicedOrder.getShopId());
|
BigDecimal packageMatFee = shopPackageMatFeeMap.get(uninvoicedOrder.getShopId());
|
||||||
if(packageMatFee.compareTo(BigDecimal.ZERO) > 0 && logisticChannelPair.getLeft().getWarehouseInChina().equalsIgnoreCase("0")) {
|
BigDecimal fretFee = price.getRegistrationFee();
|
||||||
uninvoicedOrder.setPackagingMaterialFee(packageMatFee);
|
BigDecimal pickingFee = price.getAdditionalCost();
|
||||||
}
|
BigDecimal orderServiceFee = shopServiceFeeMap.get(uninvoicedOrder.getShopId());
|
||||||
uninvoicedOrder.setFretFee(price.getRegistrationFee());
|
|
||||||
uninvoicedOrder.setPickingFee(price.getAdditionalCost());
|
|
||||||
uninvoicedOrder.setOrderServiceFee(shopServiceFeeMap.get(uninvoicedOrder.getShopId()));
|
|
||||||
uninvoicedOrder.setShippingInvoiceNumber(invoiceCode);
|
|
||||||
BigDecimal totalShippingFee = price.calculateShippingPrice(contentWeight);
|
BigDecimal totalShippingFee = price.calculateShippingPrice(contentWeight);
|
||||||
BigDecimal pickingFeePerItem = price.getPickingFeePerItem();
|
BigDecimal pickingFeePerItem = price.getPickingFeePerItem();
|
||||||
BigDecimal clientVatPercentage = client.getVatPercentage();
|
BigDecimal clientVatPercentage = client.getVatPercentage();
|
||||||
|
|
@ -560,6 +794,32 @@ public class ShippingInvoiceFactory {
|
||||||
if (vatApplicable && minimumDeclaredValue != null) {
|
if (vatApplicable && minimumDeclaredValue != null) {
|
||||||
totalVAT = calculateTotalVat(totalDeclaredValue, clientVatPercentage, minimumDeclaredValue);
|
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
|
// 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
|
// is bigger than initial total shipping fee, the remedy is to deduct from the initial total, so we never go
|
||||||
// above it
|
// above it
|
||||||
|
|
@ -570,9 +830,167 @@ public class ShippingInvoiceFactory {
|
||||||
vatApplicable, pickingFeePerItem, content, remainingShippingFee);
|
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<String, Object> 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;
|
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<String, LogisticChannel> logisticChannelMap,
|
||||||
|
PlatformOrder order,
|
||||||
|
List<PlatformOrderContent> contents,
|
||||||
|
Map<LogisticChannel, List<LogisticChannelPrice>> channelPriceMap,
|
||||||
|
List<Country> countryList,
|
||||||
|
Map<String, BigDecimal> skuRealWeights,
|
||||||
|
Map<String, BigDecimal> skuServiceFees,
|
||||||
|
List<SkuDeclaredValue> latestDeclaredValues,
|
||||||
|
Client client,
|
||||||
|
Map<String, BigDecimal> shopServiceFeeMap,
|
||||||
|
Map<String, BigDecimal> 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<String, Integer> 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<BigDecimal, List<String>> contentWeightResult = platformOrderContentService.calculateWeight(
|
||||||
|
contentSkuQtyMap,
|
||||||
|
skuRealWeights
|
||||||
|
);
|
||||||
|
if(!contentWeightResult.getValue().isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
BigDecimal contentWeight = contentWeightResult.getKey();
|
||||||
|
Pair<LogisticChannel, LogisticChannelPrice> 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<PlatformOrderContent, BigDecimal> 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<SkuQuantity> skuQuantities = platformOrderContentService.searchOrderContent(Collections.singletonList(order.getId()));
|
||||||
|
List<OrderContentDetail> 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<PlatformOrder, List<PlatformOrderContent>> orderAndContent) {
|
private void updateOrdersAndContentsInDb(Map<PlatformOrder, List<PlatformOrderContent>> orderAndContent) {
|
||||||
// update them to DB after invoiced
|
// update them to DB after invoiced
|
||||||
platformOrderService.updateBatchById(orderAndContent.keySet());
|
platformOrderService.updateBatchById(orderAndContent.keySet());
|
||||||
|
|
@ -801,7 +1219,7 @@ public class ShippingInvoiceFactory {
|
||||||
shopPackageMatFeeMap.put(shop.getId(), shop.getPackagingMaterialFee());
|
shopPackageMatFeeMap.put(shop.getId(), shop.getPackagingMaterialFee());
|
||||||
Map<PlatformOrder, List<PlatformOrderContent>> orders = uninvoicedOrdersByShopId.get(shop.getId());
|
Map<PlatformOrder, List<PlatformOrderContent>> orders = uninvoicedOrdersByShopId.get(shop.getId());
|
||||||
try {
|
try {
|
||||||
Map<String, List<String>> orderIdErrorMap = calculateFees(logisticChannelMap, orders, channelPriceMap, countryList, skuRealWeights, skuServiceFees,
|
Map<String, List<String>> orderIdErrorMap = calculateFees(null, logisticChannelMap, orders, channelPriceMap, countryList, skuRealWeights, skuServiceFees,
|
||||||
latestDeclaredValues, client, shopServiceFeeMap,shopPackageMatFeeMap, null);
|
latestDeclaredValues, client, shopServiceFeeMap,shopPackageMatFeeMap, null);
|
||||||
if(!orderIdErrorMap.isEmpty()) {
|
if(!orderIdErrorMap.isEmpty()) {
|
||||||
Map.Entry<String, List<String>> errorEntry = orderIdErrorMap.entrySet().iterator().next();
|
Map.Entry<String, List<String>> errorEntry = orderIdErrorMap.entrySet().iterator().next();
|
||||||
|
|
@ -858,7 +1276,6 @@ public class ShippingInvoiceFactory {
|
||||||
.collect(toMap(LogisticChannel::getId, Function.identity()));
|
.collect(toMap(LogisticChannel::getId, Function.identity()));
|
||||||
Map<LogisticChannel, List<LogisticChannelPrice>> channelPriceMap = getChannelPriceMap(logisticChannelMap, ordersMap, true);
|
Map<LogisticChannel, List<LogisticChannelPrice>> channelPriceMap = getChannelPriceMap(logisticChannelMap, ordersMap, true);
|
||||||
|
|
||||||
|
|
||||||
for (Shop shop : shops) {
|
for (Shop shop : shops) {
|
||||||
Map<String, BigDecimal> shopServiceFeeMap = new HashMap<>();
|
Map<String, BigDecimal> shopServiceFeeMap = new HashMap<>();
|
||||||
Map<String, BigDecimal> shopPackageMatFeeMap = new HashMap<>();
|
Map<String, BigDecimal> shopPackageMatFeeMap = new HashMap<>();
|
||||||
|
|
@ -866,24 +1283,10 @@ public class ShippingInvoiceFactory {
|
||||||
shopPackageMatFeeMap.put(shop.getId(), shop.getPackagingMaterialFee());
|
shopPackageMatFeeMap.put(shop.getId(), shop.getPackagingMaterialFee());
|
||||||
Map<PlatformOrder, List<PlatformOrderContent>> orders = uninvoicedOrdersByShopId.get(shop.getId());
|
Map<PlatformOrder, List<PlatformOrderContent>> orders = uninvoicedOrdersByShopId.get(shop.getId());
|
||||||
try {
|
try {
|
||||||
Map<PlatformOrder, List<PlatformOrderContent>> ordersCopy = new HashMap<>(orders);
|
Map<String, List<String>> platformOrderIdErrorMap = calculateFees(null, logisticChannelMap, orders, channelPriceMap, countryList, skuRealWeights, skuServiceFees,
|
||||||
Map<String, List<String>> platformOrderIdErrorMap = calculateFees(logisticChannelMap, orders, channelPriceMap, countryList, skuRealWeights, skuServiceFees,
|
|
||||||
latestDeclaredValues, client, shopServiceFeeMap, shopPackageMatFeeMap, null);
|
latestDeclaredValues, client, shopServiceFeeMap, shopPackageMatFeeMap, null);
|
||||||
System.out.println("Error List : " + platformOrderIdErrorMap);
|
platformOrderIdErrorMap.forEach((key, value) -> errorMessages.addAll(value));
|
||||||
for(Map.Entry<PlatformOrder,List<PlatformOrderContent>> entry : orders.entrySet()) {
|
orders.entrySet().removeIf(entries -> platformOrderIdErrorMap.containsKey(entries.getKey().getId()));
|
||||||
for(Map.Entry<String, List<String>> 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;
|
|
||||||
List<String> estimationsOrderIds = orders.keySet().stream().map(PlatformOrder::getId).collect(Collectors.toList());
|
List<String> estimationsOrderIds = orders.keySet().stream().map(PlatformOrder::getId).collect(Collectors.toList());
|
||||||
BigDecimal eurToUsd = exchangeRatesMapper.getLatestExchangeRate("EUR", "USD");
|
BigDecimal eurToUsd = exchangeRatesMapper.getLatestExchangeRate("EUR", "USD");
|
||||||
ShippingInvoice invoice = new ShippingInvoice(client, "", "", orders, null, eurToUsd);
|
ShippingInvoice invoice = new ShippingInvoice(client, "", "", orders, null, eurToUsd);
|
||||||
|
|
|
||||||
|
|
@ -155,12 +155,6 @@ public class Client implements Serializable {
|
||||||
@Excel(name = "公司识别码数值", width = 15)
|
@Excel(name = "公司识别码数值", width = 15)
|
||||||
@ApiModelProperty(value = "公司识别码数值")
|
@ApiModelProperty(value = "公司识别码数值")
|
||||||
private String companyIdValue;
|
private String companyIdValue;
|
||||||
/**
|
|
||||||
* 账户余额
|
|
||||||
*/
|
|
||||||
@Excel(name = "账户余额", width = 15)
|
|
||||||
@ApiModelProperty(value = "账户余额")
|
|
||||||
private BigDecimal balance;
|
|
||||||
/**
|
/**
|
||||||
* IOSS号码
|
* IOSS号码
|
||||||
*/
|
*/
|
||||||
|
|
@ -180,10 +174,32 @@ public class Client implements Serializable {
|
||||||
@Dict(dicCode = "yn")
|
@Dict(dicCode = "yn")
|
||||||
@ApiModelProperty(value = "是否活跃")
|
@ApiModelProperty(value = "是否活跃")
|
||||||
private String active;
|
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() {
|
public String fullName() {
|
||||||
return firstName + " " + surname;
|
return firstName + " " + surname;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -60,4 +60,8 @@ public class ClientCategory implements Serializable {
|
||||||
@Excel(name = "description", width = 15)
|
@Excel(name = "description", width = 15)
|
||||||
@ApiModelProperty(value = "description")
|
@ApiModelProperty(value = "description")
|
||||||
private java.lang.String 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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,9 @@ public class OrderContentDetail {
|
||||||
*/
|
*/
|
||||||
public BigDecimal totalPrice() {
|
public BigDecimal totalPrice() {
|
||||||
BigDecimal unit = skuDetail.getPrice().getPrice(quantity, exchangeRate);
|
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));
|
BigDecimal total = unit.multiply(new BigDecimal(quantity));
|
||||||
log.info("unit: {}", unit);
|
log.info("unit: {}", unit);
|
||||||
log.info("total: {}", total);
|
log.info("total: {}", total);
|
||||||
|
|
|
||||||
|
|
@ -121,7 +121,7 @@ public class SkuPrice implements Serializable {
|
||||||
priceCandidate = priceRmb.divide(eurToRmb, RoundingMode.HALF_UP);
|
priceCandidate = priceRmb.divide(eurToRmb, RoundingMode.HALF_UP);
|
||||||
discountedPriceCandidate = discountedPriceRmb == null ? priceCandidate : discountedPriceRmb.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 discountedPriceCandidate;
|
||||||
}
|
}
|
||||||
return priceCandidate;
|
return priceCandidate;
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,12 @@
|
||||||
package org.jeecg.modules.business.mapper;
|
package org.jeecg.modules.business.mapper;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.apache.ibatis.annotations.Param;
|
import org.apache.ibatis.annotations.Param;
|
||||||
import org.jeecg.modules.business.entity.ClientCategory;
|
import org.jeecg.modules.business.entity.ClientCategory;
|
||||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Description: client category
|
* @Description: client category
|
||||||
|
|
@ -12,6 +14,7 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
* @Date: 2023-10-19
|
* @Date: 2023-10-19
|
||||||
* @Version: V1.0
|
* @Version: V1.0
|
||||||
*/
|
*/
|
||||||
|
@Repository
|
||||||
public interface ClientCategoryMapper extends BaseMapper<ClientCategory> {
|
public interface ClientCategoryMapper extends BaseMapper<ClientCategory> {
|
||||||
|
BigDecimal getBalanceThresholdByCategoryId(@Param("id") String id);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ public interface ClientMapper extends BaseMapper<Client> {
|
||||||
|
|
||||||
String getClientEntity(@Param("id") String id);
|
String getClientEntity(@Param("id") String id);
|
||||||
Map<String, String> getClientsEntity(@Param("ids") List<String> ids);
|
Map<String, String> getClientsEntity(@Param("ids") List<String> ids);
|
||||||
String getClientByInternalCode(@Param("code") String code);
|
String getClientIdByCode(@Param("code") String code);
|
||||||
|
|
||||||
List<Client> getClientByType(@Param("type") String type);
|
List<Client> getClientByType(@Param("type") String type);
|
||||||
|
Client getClientByCode(@Param("code") String internalCode);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -81,4 +81,5 @@ public interface PlatformOrderContentMapper extends BaseMapper<PlatformOrderCont
|
||||||
List<SkuPrice> searchSkuPrice(@Param("skuIds") List<String> skuIds);
|
List<SkuPrice> searchSkuPrice(@Param("skuIds") List<String> skuIds);
|
||||||
|
|
||||||
void fetchHighestPriorityAttribute(PlatformOrderContent content);
|
void fetchHighestPriorityAttribute(PlatformOrderContent content);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -176,7 +176,7 @@ public interface PlatformOrderMapper extends BaseMapper<PlatformOrder> {
|
||||||
@Param("shops") List<String> shops,
|
@Param("shops") List<String> shops,
|
||||||
@Param("warehouses") List<String> warehouses);
|
@Param("warehouses") List<String> warehouses);
|
||||||
|
|
||||||
List<PlatformOrder> fetchUninvoicedShippedOrderIDInShopsAndOrderTime(@Param("startDate") String startDate,
|
List<PlatformOrder> fetchUninvoicedOrderIDInShopsAndOrderTime(@Param("startDate") String startDate,
|
||||||
@Param("endDate") String endDate,
|
@Param("endDate") String endDate,
|
||||||
@Param("shops") List<String> shops,
|
@Param("shops") List<String> shops,
|
||||||
@Param("erpStatuses") List<Integer> erpStatuses,
|
@Param("erpStatuses") List<Integer> erpStatuses,
|
||||||
|
|
@ -192,4 +192,6 @@ public interface PlatformOrderMapper extends BaseMapper<PlatformOrder> {
|
||||||
|
|
||||||
List<PlatformOrder> fetchEmptyLogisticChannelOrders(@Param("startDate") String startDate,@Param("endDate") String endDate);
|
List<PlatformOrder> fetchEmptyLogisticChannelOrders(@Param("startDate") String startDate,@Param("endDate") String endDate);
|
||||||
|
|
||||||
|
void updateErpStatusByCode(@Param("invoiceCode") String invoiceCode, @Param("erpStatus") int erpStatus);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -91,4 +91,9 @@ public interface PurchaseOrderMapper extends BaseMapper<PurchaseOrder> {
|
||||||
String getInvoiceNumber(@Param("purchaseID") String purchaseID);
|
String getInvoiceNumber(@Param("purchaseID") String purchaseID);
|
||||||
|
|
||||||
|
|
||||||
|
BigDecimal getPurchaseFeesByInvoiceCode(@Param("invoiceCode") String invoiceCode);
|
||||||
|
|
||||||
|
void deleteInvoice(@Param("invoiceNumber") String invoiceNumber);
|
||||||
|
|
||||||
|
void deleteBatchInvoice(@Param("invoiceNumbers") List<String> invoiceNumbers);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,7 @@ package org.jeecg.modules.business.mapper;
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
import org.apache.ibatis.annotations.Param;
|
import org.apache.ibatis.annotations.Param;
|
||||||
import org.jeecg.modules.business.entity.Client;
|
import org.jeecg.modules.business.entity.*;
|
||||||
import org.jeecg.modules.business.entity.PlatformOrder;
|
|
||||||
import org.jeecg.modules.business.entity.PlatformOrderContent;
|
|
||||||
import org.jeecg.modules.business.entity.ShippingInvoice;
|
|
||||||
import org.springframework.stereotype.Repository;
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
@ -23,4 +20,5 @@ public interface ShippingInvoiceMapper extends BaseMapper<ShippingInvoice> {
|
||||||
List<PlatformOrder> fetchPlatformOrder(@Param("invoiceNumber") String invoiceNumber);
|
List<PlatformOrder> fetchPlatformOrder(@Param("invoiceNumber") String invoiceNumber);
|
||||||
List<PlatformOrderContent> fetchPlatformOrderContent(@Param("platformOrderId") String platformOrderId);
|
List<PlatformOrderContent> fetchPlatformOrderContent(@Param("platformOrderId") String platformOrderId);
|
||||||
Client fetchShopOwnerFromInvoiceNumber(@Param("invoiceNumber") String invoiceNumber);
|
Client fetchShopOwnerFromInvoiceNumber(@Param("invoiceNumber") String invoiceNumber);
|
||||||
|
Currency fetchInvoiceCurrencyByCode(@Param("invoiceNumber") String invoiceCode);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,9 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||||
<mapper namespace="org.jeecg.modules.demo.business.mapper.ClientCategoryMapper">
|
<mapper namespace="org.jeecg.modules.business.mapper.ClientCategoryMapper">
|
||||||
|
<select id="getBalanceThresholdByCategoryId" resultType="java.math.BigDecimal">
|
||||||
|
SELECT balance_threshold
|
||||||
|
FROM client_category
|
||||||
|
WHERE id = #{id}
|
||||||
|
</select>
|
||||||
</mapper>
|
</mapper>
|
||||||
|
|
@ -14,10 +14,15 @@
|
||||||
#{id}
|
#{id}
|
||||||
</foreach>;
|
</foreach>;
|
||||||
</select>
|
</select>
|
||||||
<select id="getClientByInternalCode" parameterType="java.lang.String" resultType="java.lang.String">
|
<select id="getClientIdByCode" parameterType="java.lang.String" resultType="java.lang.String">
|
||||||
SELECT id
|
SELECT id
|
||||||
FROM client
|
FROM client
|
||||||
WHERE internal_code = #{code}
|
WHERE internal_code = #{code}
|
||||||
|
</select>
|
||||||
|
<select id="getClientByCode" parameterType="java.lang.String" resultType="org.jeecg.modules.business.entity.Client">
|
||||||
|
SELECT *
|
||||||
|
FROM client
|
||||||
|
WHERE internal_code = #{code}
|
||||||
</select>
|
</select>
|
||||||
<select id="getClientByType" resultType="org.jeecg.modules.business.entity.Client">
|
<select id="getClientByType" resultType="org.jeecg.modules.business.entity.Client">
|
||||||
SELECT c.*
|
SELECT c.*
|
||||||
|
|
|
||||||
|
|
@ -295,18 +295,21 @@
|
||||||
</foreach>;
|
</foreach>;
|
||||||
</insert>
|
</insert>
|
||||||
<update id="cancelInvoice">
|
<update id="cancelInvoice">
|
||||||
UPDATE platform_order_content
|
UPDATE platform_order_content poc
|
||||||
SET picking_fee = 0.0,
|
JOIN platform_order po ON poc.platform_order_id = po.id
|
||||||
shipping_fee = NULL,
|
JOIN shipping_invoice si ON po.shipping_invoice_number = si.invoice_number
|
||||||
service_fee = NULL,
|
SET poc.picking_fee = 0.0,
|
||||||
vat = NULL,
|
poc.shipping_fee = NULL,
|
||||||
purchase_fee = 0.0,
|
poc.service_fee = NULL,
|
||||||
erp_status =
|
poc.vat = NULL,
|
||||||
CASE erp_status
|
poc.purchase_fee = 0.0,
|
||||||
WHEN '4' THEN '3'
|
poc.erp_status =
|
||||||
ELSE erp_status
|
CASE
|
||||||
|
WHEN poc.erp_status = '4' THEN '3'
|
||||||
|
WHEN poc.erp_status = '2' AND si.create_by = 'system' THEN '1'
|
||||||
|
ELSE poc.erp_status
|
||||||
END
|
END
|
||||||
WHERE platform_order_id IN (SELECT id FROM platform_order WHERE shipping_invoice_number = #{invoiceNumber});
|
WHERE po.shipping_invoice_number = #{invoiceNumber};
|
||||||
</update>
|
</update>
|
||||||
<update id="cancelBatchInvoice">
|
<update id="cancelBatchInvoice">
|
||||||
UPDATE platform_order_content
|
UPDATE platform_order_content
|
||||||
|
|
|
||||||
|
|
@ -88,6 +88,14 @@
|
||||||
WHERE id = #{orderID}
|
WHERE id = #{orderID}
|
||||||
</update>
|
</update>
|
||||||
|
|
||||||
|
<update id="updateErpStatusByCode">
|
||||||
|
UPDATE platform_order po, platform_order_content poc
|
||||||
|
SET po.erp_status = #{erpStatus},
|
||||||
|
poc.erp_status = #{erpStatus}
|
||||||
|
WHERE po.shipping_invoice_number = #{invoiceCode}
|
||||||
|
AND poc.platform_order_id = po.id;
|
||||||
|
</update>
|
||||||
|
|
||||||
<update id="batchUpdateStatus">
|
<update id="batchUpdateStatus">
|
||||||
UPDATE platform_order
|
UPDATE platform_order
|
||||||
SET status = #{status}
|
SET status = #{status}
|
||||||
|
|
@ -488,7 +496,7 @@
|
||||||
AND po.shipping_time between #{startDate} AND #{endDate}
|
AND po.shipping_time between #{startDate} AND #{endDate}
|
||||||
AND po.erp_status = 3;
|
AND po.erp_status = 3;
|
||||||
</select>
|
</select>
|
||||||
<select id="fetchUninvoicedShippedOrderIDInShopsAndOrderTime" resultType="org.jeecg.modules.business.entity.PlatformOrder">
|
<select id="fetchUninvoicedOrderIDInShopsAndOrderTime" resultType="org.jeecg.modules.business.entity.PlatformOrder">
|
||||||
SELECT po.id
|
SELECT po.id
|
||||||
FROM platform_order po
|
FROM platform_order po
|
||||||
JOIN logistic_channel lc ON po.logistic_channel_name = lc.zh_name
|
JOIN logistic_channel lc ON po.logistic_channel_name = lc.zh_name
|
||||||
|
|
@ -643,15 +651,17 @@
|
||||||
</insert>
|
</insert>
|
||||||
|
|
||||||
<update id="cancelInvoice">
|
<update id="cancelInvoice">
|
||||||
UPDATE platform_order
|
UPDATE platform_order po
|
||||||
|
JOIN shipping_invoice si ON po.shipping_invoice_number = si.invoice_number
|
||||||
SET fret_fee = NULL,
|
SET fret_fee = NULL,
|
||||||
order_service_fee = NULL,
|
order_service_fee = NULL,
|
||||||
shipping_invoice_number = NULL,
|
shipping_invoice_number = NULL,
|
||||||
picking_fee = 0.0,
|
picking_fee = 0.0,
|
||||||
packaging_material_fee = 0.0,
|
packaging_material_fee = 0.0,
|
||||||
erp_status =
|
erp_status =
|
||||||
CASE erp_status
|
CASE
|
||||||
WHEN '4' THEN '3'
|
WHEN erp_status = '4' THEN '3'
|
||||||
|
WHEN erp_status = '2' AND si.create_by = 'system' THEN '1'
|
||||||
ELSE erp_status
|
ELSE erp_status
|
||||||
END
|
END
|
||||||
WHERE shipping_invoice_number = #{invoiceNumber};
|
WHERE shipping_invoice_number = #{invoiceNumber};
|
||||||
|
|
|
||||||
|
|
@ -63,4 +63,22 @@
|
||||||
FROM purchase_order
|
FROM purchase_order
|
||||||
WHERE id = #{purchaseID}
|
WHERE id = #{purchaseID}
|
||||||
</select>
|
</select>
|
||||||
|
<select id="getPurchaseFeesByInvoiceCode" resultType="java.math.BigDecimal">
|
||||||
|
SELECT final_amount
|
||||||
|
FROM purchase_order
|
||||||
|
WHERE invoice_number = #{invoiceCode};
|
||||||
|
</select>
|
||||||
|
<delete id="deleteInvoice">
|
||||||
|
DELETE
|
||||||
|
FROM purchase_order
|
||||||
|
WHERE invoice_number = #{invoiceNumber}
|
||||||
|
</delete>
|
||||||
|
<delete id="deleteBatchInvoice">
|
||||||
|
DELETE
|
||||||
|
FROM purchase_order
|
||||||
|
WHERE invoice_number IN
|
||||||
|
<foreach collection="invoiceNumbers" item="invoiceNumber" index="index" open="(" separator="," close=")">
|
||||||
|
#{invoiceNumber}
|
||||||
|
</foreach>
|
||||||
|
</delete>
|
||||||
</mapper>
|
</mapper>
|
||||||
|
|
|
||||||
|
|
@ -29,4 +29,10 @@
|
||||||
FROM platform_order_content p
|
FROM platform_order_content p
|
||||||
WHERE p.platform_order_id = #{platformOrderId}
|
WHERE p.platform_order_id = #{platformOrderId}
|
||||||
</select>
|
</select>
|
||||||
|
<select id="fetchInvoiceCurrencyByCode" resultType="org.jeecg.modules.business.entity.Currency">
|
||||||
|
SELECT c.id, c.code
|
||||||
|
FROM shipping_invoice s
|
||||||
|
JOIN currency c ON s.currency_id = c.id
|
||||||
|
WHERE invoice_number = #{invoiceNumber}
|
||||||
|
</select>
|
||||||
</mapper>
|
</mapper>
|
||||||
|
|
@ -5,10 +5,12 @@ import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;
|
||||||
import javax.mail.MessagingException;
|
import javax.mail.MessagingException;
|
||||||
import javax.mail.Session;
|
import javax.mail.Session;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
public interface EmailService {
|
public interface EmailService {
|
||||||
public void sendSimpleMessage(String recipient, String subject, String text, Session session) throws MessagingException;
|
public void sendSimpleMessage(String recipient, String subject, String text, Session session) throws MessagingException;
|
||||||
|
public void newSendSimpleMessage(String recipient, String subject, String templateName, Map<String, Object> templateModel) throws MessagingException;
|
||||||
public void sendMessageWithAttachment(String recipient, String subject, String text, String attachment, Session session) throws MessagingException, IOException;
|
public void sendMessageWithAttachment(String recipient, String subject, String text, String attachment, Session session) throws MessagingException, IOException;
|
||||||
public Properties getMailSender();
|
public Properties getMailSender();
|
||||||
public FreeMarkerConfigurer freemarkerClassLoaderConfig() throws IOException;
|
public FreeMarkerConfigurer freemarkerClassLoaderConfig() throws IOException;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,10 @@
|
||||||
package org.jeecg.modules.business.service;
|
package org.jeecg.modules.business.service;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
import org.jeecg.modules.business.entity.Balance;
|
import org.jeecg.modules.business.entity.Balance;
|
||||||
import com.baomidou.mybatisplus.extension.service.IService;
|
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 org.jeecg.modules.business.vo.InvoiceMetaData;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
|
@ -37,4 +40,11 @@ public interface IBalanceService extends IService<Balance> {
|
||||||
void editBalance(String operationId, String operationType, String clientId, BigDecimal amount, String currencyId) throws Exception;
|
void editBalance(String operationId, String operationType, String clientId, BigDecimal amount, String currencyId) throws Exception;
|
||||||
|
|
||||||
void deleteBatchBalance(List<String> operationIds, String operationType);
|
void deleteBatchBalance(List<String> operationIds, String operationType);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get low balance clients from client list
|
||||||
|
* @param metaDataList list of meta data
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
List<BalanceData> getLowBalanceClients(List<InvoiceMetaData> metaDataList);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ public interface IClientService extends IService<Client> {
|
||||||
public void delBatchMain (Collection<? extends Serializable> idList);
|
public void delBatchMain (Collection<? extends Serializable> idList);
|
||||||
public String getClientEntity(String id);
|
public String getClientEntity(String id);
|
||||||
public Map<String, String> getClientsEntity(List<String> ids);
|
public Map<String, String> getClientsEntity(List<String> ids);
|
||||||
public String getClientByInternalCode(String code);
|
public String getClientIdByCode(String code);
|
||||||
/**
|
/**
|
||||||
* Get current user's client information
|
* Get current user's client information
|
||||||
* @return client or null if current user's role is not client
|
* @return client or null if current user's role is not client
|
||||||
|
|
|
||||||
|
|
@ -54,4 +54,5 @@ public interface IPlatformOrderContentService extends IService<PlatformOrderCont
|
||||||
* @param invoiceNumbers
|
* @param invoiceNumbers
|
||||||
*/
|
*/
|
||||||
void cancelBatchInvoice(List<String> invoiceNumbers);
|
void cancelBatchInvoice(List<String> invoiceNumbers);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ package org.jeecg.modules.business.service;
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
import com.baomidou.mybatisplus.extension.service.IService;
|
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.entity.*;
|
||||||
import org.jeecg.modules.business.vo.PlatformOrderQuantity;
|
import org.jeecg.modules.business.vo.PlatformOrderQuantity;
|
||||||
import org.jeecg.modules.business.vo.SkuQuantity;
|
import org.jeecg.modules.business.vo.SkuQuantity;
|
||||||
|
|
@ -54,19 +55,19 @@ public interface IPlatformOrderService extends IService<PlatformOrder> {
|
||||||
|
|
||||||
void processedPlatformOrderPage(IPage<ClientPlatformOrderPage> page);
|
void processedPlatformOrderPage(IPage<ClientPlatformOrderPage> page);
|
||||||
|
|
||||||
OrdersStatisticData getPlatformOrdersStatisticData(List<String> orderIds);
|
OrdersStatisticData getPlatformOrdersStatisticData(List<String> orderIds) throws UserException;
|
||||||
|
|
||||||
List<PlatformOrderContent> selectByMainId(String mainId);
|
List<PlatformOrderContent> selectByMainId(String mainId);
|
||||||
|
|
||||||
List<ClientPlatformOrderContent> selectClientVersionByMainId(String mainId);
|
List<ClientPlatformOrderContent> selectClientVersionByMainId(String mainId);
|
||||||
|
|
||||||
PurchaseConfirmation confirmPurchaseByPlatformOrder(List<String> platformOrderIdList);
|
PurchaseConfirmation confirmPurchaseByPlatformOrder(List<String> platformOrderIdList) throws UserException;
|
||||||
|
|
||||||
PurchaseConfirmation confirmPurchaseBySkuQuantity(List<SkuQuantity> skuIDQuantityMap);
|
PurchaseConfirmation confirmPurchaseBySkuQuantity(List<SkuQuantity> skuIDQuantityMap) throws UserException;
|
||||||
|
|
||||||
PurchaseConfirmation confirmPurchaseBySkuQuantity(ClientInfo clientInfo, List<SkuQuantity> skuIDQuantityMap);
|
PurchaseConfirmation confirmPurchaseBySkuQuantity(ClientInfo clientInfo, List<SkuQuantity> skuIDQuantityMap) throws UserException;
|
||||||
|
|
||||||
List<OrderContentDetail> searchPurchaseOrderDetail(List<SkuQuantity> skuQuantities);
|
List<OrderContentDetail> searchPurchaseOrderDetail(List<SkuQuantity> skuQuantities) throws UserException;
|
||||||
|
|
||||||
OrderQuantity queryOrderQuantities();
|
OrderQuantity queryOrderQuantities();
|
||||||
|
|
||||||
|
|
@ -199,4 +200,5 @@ public interface IPlatformOrderService extends IService<PlatformOrder> {
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
List<PlatformOrder> fetchEmptyLogisticChannelOrders(String startDate, String endDate);
|
List<PlatformOrder> fetchEmptyLogisticChannelOrders(String startDate, String endDate);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ package org.jeecg.modules.business.service;
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
import com.baomidou.mybatisplus.extension.service.IService;
|
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.domain.purchase.invoice.InvoiceData;
|
||||||
import org.jeecg.modules.business.entity.*;
|
import org.jeecg.modules.business.entity.*;
|
||||||
import org.jeecg.modules.business.vo.SkuQuantity;
|
import org.jeecg.modules.business.vo.SkuQuantity;
|
||||||
|
|
@ -10,6 +11,7 @@ import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
import java.math.BigDecimal;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
@ -49,7 +51,7 @@ public interface IPurchaseOrderService extends IService<PurchaseOrder> {
|
||||||
*/
|
*/
|
||||||
void setPageForCurrentClient(IPage<PurchaseOrder> page);
|
void setPageForCurrentClient(IPage<PurchaseOrder> page);
|
||||||
|
|
||||||
String addPurchase(List<SkuQuantity> skuQuantities);
|
String addPurchase(List<SkuQuantity> skuQuantities) throws UserException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a new purchase. The purchase contains sku and its quantity indicated by
|
* Add a new purchase. The purchase contains sku and its quantity indicated by
|
||||||
|
|
@ -65,10 +67,10 @@ public interface IPurchaseOrderService extends IService<PurchaseOrder> {
|
||||||
* @return the new purchase order identifier
|
* @return the new purchase order identifier
|
||||||
*/
|
*/
|
||||||
@Transactional
|
@Transactional
|
||||||
String addPurchase(List<SkuQuantity> SkuQuantity, List<String> orderIDs);
|
String addPurchase(List<SkuQuantity> SkuQuantity, List<String> orderIDs) throws UserException;
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
String addPurchase(String username, Client client, String invoiceNumber, List<SkuQuantity> skuQuantities, Map<PlatformOrder, List<PlatformOrderContent>> platformOrderIDs);
|
String addPurchase(String username, Client client, String invoiceNumber, List<SkuQuantity> skuQuantities, Map<PlatformOrder, List<PlatformOrderContent>> platformOrderIDs) throws UserException;
|
||||||
|
|
||||||
void savePaymentDocumentForPurchase(String purchaseID, MultipartFile in) throws IOException;
|
void savePaymentDocumentForPurchase(String purchaseID, MultipartFile in) throws IOException;
|
||||||
|
|
||||||
|
|
@ -105,4 +107,10 @@ public interface IPurchaseOrderService extends IService<PurchaseOrder> {
|
||||||
InvoiceData makeInvoice(String purchaseID) throws IOException, URISyntaxException;
|
InvoiceData makeInvoice(String purchaseID) throws IOException, URISyntaxException;
|
||||||
|
|
||||||
byte[] getInvoiceByte(String invoiceCode) throws IOException;
|
byte[] getInvoiceByte(String invoiceCode) throws IOException;
|
||||||
|
|
||||||
|
BigDecimal getPurchaseFeesByInvoiceCode(String invoiceCode);
|
||||||
|
|
||||||
|
void cancelInvoice(String invoiceNumber);
|
||||||
|
|
||||||
|
void cancelBatchInvoice(List<String> invoiceNumbers);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,6 @@
|
||||||
package org.jeecg.modules.business.service;
|
package org.jeecg.modules.business.service;
|
||||||
|
|
||||||
import org.jeecg.modules.business.entity.Client;
|
import org.jeecg.modules.business.entity.*;
|
||||||
import org.jeecg.modules.business.entity.PlatformOrder;
|
|
||||||
import org.jeecg.modules.business.entity.PlatformOrderContent;
|
|
||||||
import org.jeecg.modules.business.entity.ShippingInvoice;
|
|
||||||
import com.baomidou.mybatisplus.extension.service.IService;
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
|
@ -42,4 +39,5 @@ public interface IShippingInvoiceService extends IService<ShippingInvoice> {
|
||||||
public List<PlatformOrder> getPlatformOrder(String invoiceNumber);
|
public List<PlatformOrder> getPlatformOrder(String invoiceNumber);
|
||||||
public List<PlatformOrderContent> getPlatformOrderContent(String platformOrderId);
|
public List<PlatformOrderContent> getPlatformOrderContent(String platformOrderId);
|
||||||
public Client getShopOwnerFromInvoiceNumber(String invoiceNumber);
|
public Client getShopOwnerFromInvoiceNumber(String invoiceNumber);
|
||||||
|
Currency getInvoiceCurrencyByCode(String invoiceCode);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,9 +17,11 @@ import org.jeecg.modules.business.vo.*;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.core.env.Environment;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import javax.mail.MessagingException;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
|
|
@ -52,6 +54,8 @@ public class PlatformOrderShippingInvoiceService {
|
||||||
@Autowired
|
@Autowired
|
||||||
ClientMapper clientMapper;
|
ClientMapper clientMapper;
|
||||||
@Autowired
|
@Autowired
|
||||||
|
EmailService emailService;
|
||||||
|
@Autowired
|
||||||
ShopMapper shopMapper;
|
ShopMapper shopMapper;
|
||||||
@Autowired
|
@Autowired
|
||||||
LogisticChannelPriceMapper logisticChannelPriceMapper;
|
LogisticChannelPriceMapper logisticChannelPriceMapper;
|
||||||
|
|
@ -81,7 +85,8 @@ public class PlatformOrderShippingInvoiceService {
|
||||||
ISavRefundWithDetailService savRefundWithDetailService;
|
ISavRefundWithDetailService savRefundWithDetailService;
|
||||||
@Autowired
|
@Autowired
|
||||||
ISavRefundService savRefundService;
|
ISavRefundService savRefundService;
|
||||||
|
@Autowired
|
||||||
|
Environment env;
|
||||||
@Value("${jeecg.path.shippingTemplatePath_EU}")
|
@Value("${jeecg.path.shippingTemplatePath_EU}")
|
||||||
private String SHIPPING_INVOICE_TEMPLATE_EU;
|
private String SHIPPING_INVOICE_TEMPLATE_EU;
|
||||||
|
|
||||||
|
|
@ -140,6 +145,8 @@ public class PlatformOrderShippingInvoiceService {
|
||||||
}
|
}
|
||||||
public Period getValidOrderTimePeriod(List<String> shopIDs, List<Integer> erpStatuses) {
|
public Period getValidOrderTimePeriod(List<String> shopIDs, List<Integer> erpStatuses) {
|
||||||
Date begin = platformOrderMapper.findEarliestUninvoicedPlatformOrderTime(shopIDs, erpStatuses);
|
Date begin = platformOrderMapper.findEarliestUninvoicedPlatformOrderTime(shopIDs, erpStatuses);
|
||||||
|
if(begin == null)
|
||||||
|
return null;
|
||||||
ZoneId shanghai = ZoneId.of("Asia/Shanghai");
|
ZoneId shanghai = ZoneId.of("Asia/Shanghai");
|
||||||
ZoneId paris = ZoneId.of("Europe/Paris");
|
ZoneId paris = ZoneId.of("Europe/Paris");
|
||||||
LocalDateTime ldt = LocalDateTime.ofInstant(begin.toInstant(), shanghai);
|
LocalDateTime ldt = LocalDateTime.ofInstant(begin.toInstant(), shanghai);
|
||||||
|
|
@ -164,27 +171,21 @@ public class PlatformOrderShippingInvoiceService {
|
||||||
* @throws IOException exception related to invoice file IO.
|
* @throws IOException exception related to invoice file IO.
|
||||||
*/
|
*/
|
||||||
@Transactional
|
@Transactional
|
||||||
public InvoiceMetaData makeInvoice(ShippingInvoiceParam param) throws UserException, ParseException, IOException {
|
public InvoiceMetaData makeInvoice(ShippingInvoiceParam param, String ... user) throws UserException, ParseException, IOException {
|
||||||
// Creates factory
|
// Creates factory
|
||||||
ShippingInvoiceFactory factory = new ShippingInvoiceFactory(
|
ShippingInvoiceFactory factory = new ShippingInvoiceFactory(
|
||||||
platformOrderService, clientMapper, shopMapper, logisticChannelMapper, logisticChannelPriceMapper,
|
platformOrderService, clientMapper, shopMapper, logisticChannelMapper, logisticChannelPriceMapper,
|
||||||
platformOrderContentService, skuDeclaredValueService, countryService, exchangeRatesMapper,
|
platformOrderContentService, skuDeclaredValueService, countryService, exchangeRatesMapper,
|
||||||
purchaseOrderService, purchaseOrderContentMapper, skuPromotionHistoryMapper, savRefundService, savRefundWithDetailService);
|
purchaseOrderService, purchaseOrderContentMapper, skuPromotionHistoryMapper, savRefundService, savRefundWithDetailService, emailService, env);
|
||||||
Subject subject = null;
|
String username = user.length > 0 ? user[0] : ((LoginUser) SecurityUtils.getSubject().getPrincipal()).getUsername();
|
||||||
try {
|
|
||||||
subject = SecurityUtils.getSubject();
|
|
||||||
}
|
|
||||||
catch (Exception e) {
|
|
||||||
log.error("Error while getting subject", e);
|
|
||||||
}
|
|
||||||
String username = subject == null ? "admin" : ((LoginUser) subject.getPrincipal()).getUsername();
|
|
||||||
// Creates invoice by factory
|
// Creates invoice by factory
|
||||||
ShippingInvoice invoice = factory.createInvoice(param.clientID(),
|
ShippingInvoice invoice = factory.createInvoice(param.clientID(),
|
||||||
param.shopIDs(),
|
param.shopIDs(),
|
||||||
param.start(),
|
param.start(),
|
||||||
param.end(),
|
param.end(),
|
||||||
param.getErpStatuses(),
|
param.getErpStatuses(),
|
||||||
param.getWarehouses()
|
param.getWarehouses(),
|
||||||
|
param.getBalance()
|
||||||
);
|
);
|
||||||
// Chooses invoice template based on client's preference on currency
|
// Chooses invoice template based on client's preference on currency
|
||||||
return getInvoiceMetaData(username, invoice);
|
return getInvoiceMetaData(username, invoice);
|
||||||
|
|
@ -206,7 +207,7 @@ public class PlatformOrderShippingInvoiceService {
|
||||||
ShippingInvoiceFactory factory = new ShippingInvoiceFactory(
|
ShippingInvoiceFactory factory = new ShippingInvoiceFactory(
|
||||||
platformOrderService, clientMapper, shopMapper, logisticChannelMapper, logisticChannelPriceMapper,
|
platformOrderService, clientMapper, shopMapper, logisticChannelMapper, logisticChannelPriceMapper,
|
||||||
platformOrderContentService, skuDeclaredValueService, countryService, exchangeRatesMapper,
|
platformOrderContentService, skuDeclaredValueService, countryService, exchangeRatesMapper,
|
||||||
purchaseOrderService, purchaseOrderContentMapper, skuPromotionHistoryMapper, savRefundService, savRefundWithDetailService);
|
purchaseOrderService, purchaseOrderContentMapper, skuPromotionHistoryMapper, savRefundService, savRefundWithDetailService, emailService, env);
|
||||||
String username = ((LoginUser) SecurityUtils.getSubject().getPrincipal()).getUsername();
|
String username = ((LoginUser) SecurityUtils.getSubject().getPrincipal()).getUsername();
|
||||||
// Creates invoice by factory
|
// Creates invoice by factory
|
||||||
ShippingInvoice invoice = factory.createShippingInvoice(param.clientID(), param.orderIds(), param.getType(), param.getStart(), param.getEnd());
|
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.
|
* @throws IOException exception related to invoice file IO.
|
||||||
*/
|
*/
|
||||||
@Transactional
|
@Transactional
|
||||||
public InvoiceMetaData makeCompleteInvoice(ShippingInvoiceOrderParam param) throws UserException, ParseException, IOException {
|
public InvoiceMetaData makeCompleteInvoice(ShippingInvoiceOrderParam param) throws UserException, ParseException, IOException, MessagingException {
|
||||||
// Creates factory
|
// Creates factory
|
||||||
ShippingInvoiceFactory factory = new ShippingInvoiceFactory(
|
ShippingInvoiceFactory factory = new ShippingInvoiceFactory(
|
||||||
platformOrderService, clientMapper, shopMapper, logisticChannelMapper, logisticChannelPriceMapper,
|
platformOrderService, clientMapper, shopMapper, logisticChannelMapper, logisticChannelPriceMapper,
|
||||||
platformOrderContentService, skuDeclaredValueService, countryService, exchangeRatesMapper,
|
platformOrderContentService, skuDeclaredValueService, countryService, exchangeRatesMapper,
|
||||||
purchaseOrderService, purchaseOrderContentMapper, skuPromotionHistoryMapper, savRefundService, savRefundWithDetailService);
|
purchaseOrderService, purchaseOrderContentMapper, skuPromotionHistoryMapper, savRefundService, savRefundWithDetailService, emailService, env);
|
||||||
String username = ((LoginUser) SecurityUtils.getSubject().getPrincipal()).getUsername();
|
String username = ((LoginUser) SecurityUtils.getSubject().getPrincipal()).getUsername();
|
||||||
// Creates invoice by factory
|
// 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);
|
return getInvoiceMetaData(username, invoice);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -246,25 +247,25 @@ public class PlatformOrderShippingInvoiceService {
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
@Transactional
|
@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
|
// Creates factory
|
||||||
ShippingInvoiceFactory factory = new ShippingInvoiceFactory(
|
ShippingInvoiceFactory factory = new ShippingInvoiceFactory(
|
||||||
platformOrderService, clientMapper, shopMapper, logisticChannelMapper, logisticChannelPriceMapper,
|
platformOrderService, clientMapper, shopMapper, logisticChannelMapper, logisticChannelPriceMapper,
|
||||||
platformOrderContentService, skuDeclaredValueService, countryService, exchangeRatesMapper,
|
platformOrderContentService, skuDeclaredValueService, countryService, exchangeRatesMapper,
|
||||||
purchaseOrderService, purchaseOrderContentMapper, skuPromotionHistoryMapper, savRefundService, savRefundWithDetailService);
|
purchaseOrderService, purchaseOrderContentMapper, skuPromotionHistoryMapper, savRefundService, savRefundWithDetailService, emailService, env);
|
||||||
String username = ((LoginUser) SecurityUtils.getSubject().getPrincipal()).getUsername();
|
String username = user.length > 0 ? user[0] : ((LoginUser) SecurityUtils.getSubject().getPrincipal()).getUsername();
|
||||||
List<PlatformOrder> platformOrderList;
|
List<PlatformOrder> platformOrderList;
|
||||||
if(method.equals("post")) {
|
if(method.equals("post")) {
|
||||||
//On récupère les commandes entre 2 dates d'expédition avec un status 3
|
//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());
|
platformOrderList = platformOrderMapper.fetchUninvoicedShippedOrderIDInShops(param.getStart(), param.getEnd(), param.shopIDs(), param.getWarehouses());
|
||||||
} else {
|
} else {
|
||||||
// On récupère les commandes entre 2 dates de commandes avec un status (1,2) ou (1,2,3)
|
// 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
|
// on récupère seulement les ID des commandes
|
||||||
List<String> orderIds = platformOrderList.stream().map(PlatformOrder::getId).collect(Collectors.toList());
|
List<String> orderIds = platformOrderList.stream().map(PlatformOrder::getId).collect(Collectors.toList());
|
||||||
// Creates invoice by factory
|
// 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);
|
return getInvoiceMetaData(username, invoice);
|
||||||
}
|
}
|
||||||
@NotNull
|
@NotNull
|
||||||
|
|
@ -316,7 +317,7 @@ public class PlatformOrderShippingInvoiceService {
|
||||||
ShippingInvoiceFactory factory = new ShippingInvoiceFactory(
|
ShippingInvoiceFactory factory = new ShippingInvoiceFactory(
|
||||||
platformOrderService, clientMapper, shopMapper, logisticChannelMapper, logisticChannelPriceMapper,
|
platformOrderService, clientMapper, shopMapper, logisticChannelMapper, logisticChannelPriceMapper,
|
||||||
platformOrderContentService, skuDeclaredValueService, countryService, exchangeRatesMapper,
|
platformOrderContentService, skuDeclaredValueService, countryService, exchangeRatesMapper,
|
||||||
purchaseOrderService, purchaseOrderContentMapper, skuPromotionHistoryMapper, savRefundService, savRefundWithDetailService);
|
purchaseOrderService, purchaseOrderContentMapper, skuPromotionHistoryMapper, savRefundService, savRefundWithDetailService, emailService, env);
|
||||||
return factory.getEstimations(errorMessages);
|
return factory.getEstimations(errorMessages);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -331,7 +332,7 @@ public class PlatformOrderShippingInvoiceService {
|
||||||
ShippingInvoiceFactory factory = new ShippingInvoiceFactory(
|
ShippingInvoiceFactory factory = new ShippingInvoiceFactory(
|
||||||
platformOrderService, clientMapper, shopMapper, logisticChannelMapper, logisticChannelPriceMapper,
|
platformOrderService, clientMapper, shopMapper, logisticChannelMapper, logisticChannelPriceMapper,
|
||||||
platformOrderContentService, skuDeclaredValueService, countryService, exchangeRatesMapper,
|
platformOrderContentService, skuDeclaredValueService, countryService, exchangeRatesMapper,
|
||||||
purchaseOrderService, purchaseOrderContentMapper, skuPromotionHistoryMapper, savRefundService, savRefundWithDetailService);
|
purchaseOrderService, purchaseOrderContentMapper, skuPromotionHistoryMapper, savRefundService, savRefundWithDetailService, emailService, env);
|
||||||
return factory.getEstimations(clientId, orderIds, errorMessages);
|
return factory.getEstimations(clientId, orderIds, errorMessages);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -483,7 +484,7 @@ public class PlatformOrderShippingInvoiceService {
|
||||||
"\nclient : " + entry.getKey() +
|
"\nclient : " + entry.getKey() +
|
||||||
"\nbetween dates : [" + start + "] --- [" + end + "]");
|
"\nbetween dates : [" + start + "] --- [" + end + "]");
|
||||||
try {
|
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;
|
InvoiceMetaData metaData;
|
||||||
if(invoiceType == 0) {
|
if(invoiceType == 0) {
|
||||||
metaData = makeInvoice(param);
|
metaData = makeInvoice(param);
|
||||||
|
|
@ -498,6 +499,62 @@ public class PlatformOrderShippingInvoiceService {
|
||||||
String internalCode = clientMapper.selectById(entry.getKey()).getInternalCode();
|
String internalCode = clientMapper.selectById(entry.getKey()).getInternalCode();
|
||||||
invoiceList.add(new InvoiceMetaData("", "error", internalCode, entry.getKey(), e.getMessage()));
|
invoiceList.add(new InvoiceMetaData("", "error", internalCode, entry.getKey(), e.getMessage()));
|
||||||
log.error(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<InvoiceMetaData> breakdownInvoiceClientByTypeAndBalance(List<BalanceData> balanceDataList, int invoiceType) {
|
||||||
|
Map<BalanceData, List<String>> clientShopIDsMap = new HashMap<>();
|
||||||
|
List<InvoiceMetaData> invoiceList = new ArrayList<>();
|
||||||
|
for(BalanceData data: balanceDataList) {
|
||||||
|
String id = data.getClient().getId();
|
||||||
|
clientShopIDsMap.put(data, shopService.listIdByClient(id));
|
||||||
|
}
|
||||||
|
for(Map.Entry<BalanceData, List<String>> 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();
|
System.gc();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,14 @@
|
||||||
package org.jeecg.modules.business.service.impl;
|
package org.jeecg.modules.business.service.impl;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.jeecg.modules.business.entity.Balance;
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
import org.jeecg.modules.business.entity.PlatformOrder;
|
import org.jeecg.modules.business.entity.*;
|
||||||
import org.jeecg.modules.business.entity.PlatformOrderContent;
|
|
||||||
import org.jeecg.modules.business.entity.ShippingInvoice;
|
|
||||||
import org.jeecg.modules.business.mapper.BalanceMapper;
|
import org.jeecg.modules.business.mapper.BalanceMapper;
|
||||||
import org.jeecg.modules.business.service.IBalanceService;
|
import org.jeecg.modules.business.mapper.ClientCategoryMapper;
|
||||||
import org.jeecg.modules.business.service.ICurrencyService;
|
import org.jeecg.modules.business.mapper.ClientMapper;
|
||||||
import org.jeecg.modules.business.service.IPlatformOrderService;
|
import org.jeecg.modules.business.service.*;
|
||||||
import org.jeecg.modules.business.service.IShippingInvoiceService;
|
import org.jeecg.modules.business.vo.BalanceData;
|
||||||
|
import org.jeecg.modules.business.vo.InvoiceMetaData;
|
||||||
import org.jeecg.modules.system.entity.SysUser;
|
import org.jeecg.modules.system.entity.SysUser;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
@ -17,6 +16,7 @@ import org.springframework.stereotype.Service;
|
||||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
@ -33,11 +33,17 @@ public class BalanceServiceImpl extends ServiceImpl<BalanceMapper, Balance> impl
|
||||||
@Autowired
|
@Autowired
|
||||||
private BalanceMapper balanceMapper;
|
private BalanceMapper balanceMapper;
|
||||||
@Autowired
|
@Autowired
|
||||||
|
private ClientCategoryMapper clientCategoryMapper;
|
||||||
|
@Autowired
|
||||||
|
private ClientMapper clientMapper;
|
||||||
|
@Autowired
|
||||||
private ICurrencyService currencyService;
|
private ICurrencyService currencyService;
|
||||||
@Autowired
|
@Autowired
|
||||||
private IPlatformOrderService platformOrderService;
|
private IPlatformOrderService platformOrderService;
|
||||||
@Autowired
|
@Autowired
|
||||||
IShippingInvoiceService iShippingInvoiceService;
|
private IPurchaseOrderService purchaseOrderService;
|
||||||
|
@Autowired
|
||||||
|
IShippingInvoiceService shippingInvoiceService;
|
||||||
@Override
|
@Override
|
||||||
public BigDecimal getBalanceByClientIdAndCurrency(String clientId, String currency) {
|
public BigDecimal getBalanceByClientIdAndCurrency(String clientId, String currency) {
|
||||||
return balanceMapper.getBalanceByClientIdAndCurrency(clientId, currency);
|
return balanceMapper.getBalanceByClientIdAndCurrency(clientId, currency);
|
||||||
|
|
@ -47,20 +53,13 @@ public class BalanceServiceImpl extends ServiceImpl<BalanceMapper, Balance> impl
|
||||||
public void updateBalance(String clientId, String invoiceCode, String invoiceType) {
|
public void updateBalance(String clientId, String invoiceCode, String invoiceType) {
|
||||||
|
|
||||||
// balance update
|
// balance update
|
||||||
ShippingInvoice invoice = iShippingInvoiceService.getShippingInvoice(invoiceCode);
|
ShippingInvoice invoice = shippingInvoiceService.getShippingInvoice(invoiceCode);
|
||||||
String currency = currencyService.getCodeById(invoice.getCurrencyId());
|
String currency = currencyService.getCodeById(invoice.getCurrencyId());
|
||||||
BigDecimal previousBalance = getBalanceByClientIdAndCurrency(clientId, currency);
|
BigDecimal previousBalance = getBalanceByClientIdAndCurrency(clientId, currency);
|
||||||
BigDecimal currentBalance = previousBalance.subtract(invoice.getFinalAmount());
|
BigDecimal currentBalance = previousBalance.subtract(invoice.getFinalAmount());
|
||||||
if(invoiceType.equals("complete")) {
|
if(invoiceType.equals("complete")) {
|
||||||
List<String> orderIds = iShippingInvoiceService.getPlatformOrder(invoiceCode).stream().map(PlatformOrder::getId).collect(Collectors.toList());
|
BigDecimal purchaseFees = purchaseOrderService.getPurchaseFeesByInvoiceCode(invoiceCode);
|
||||||
Map<PlatformOrder, List<PlatformOrderContent>> orderMap = platformOrderService.fetchOrderData(orderIds);
|
currentBalance = currentBalance.subtract(purchaseFees);
|
||||||
BigDecimal purchaseFees = BigDecimal.ZERO;
|
|
||||||
for(Map.Entry<PlatformOrder, List<PlatformOrderContent>> entry : orderMap.entrySet()) {
|
|
||||||
for(PlatformOrderContent content : entry.getValue()) {
|
|
||||||
purchaseFees = purchaseFees.add(content.getPurchaseFee());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
currentBalance = currentBalance.add(purchaseFees);
|
|
||||||
}
|
}
|
||||||
SysUser sysUser = new SysUser();
|
SysUser sysUser = new SysUser();
|
||||||
Balance balance = Balance.of(sysUser.getUsername(), clientId, invoice.getCurrencyId(), Balance.OperationType.Debit.name(), invoice.getId(), currentBalance);
|
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<BalanceMapper, Balance> impl
|
||||||
public void deleteBatchBalance(List<String> operationIds, String operationType) {
|
public void deleteBatchBalance(List<String> operationIds, String operationType) {
|
||||||
balanceMapper.deleteBatchBalance(operationIds, operationType);
|
balanceMapper.deleteBatchBalance(operationIds, operationType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void editBalance(String operationId, String operationType, String clientId, BigDecimal amount, String currencyId) throws Exception {
|
public void editBalance(String operationId, String operationType, String clientId, BigDecimal amount, String currencyId) throws Exception {
|
||||||
log.info("editing balance");
|
log.info("editing balance");
|
||||||
|
|
@ -105,4 +105,20 @@ public class BalanceServiceImpl extends ServiceImpl<BalanceMapper, Balance> impl
|
||||||
balanceMapper.insert(newBalance);
|
balanceMapper.insert(newBalance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<BalanceData> getLowBalanceClients(List<InvoiceMetaData> metaDataList) {
|
||||||
|
List<BalanceData> 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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -133,7 +133,7 @@ public class ClientServiceImpl extends ServiceImpl<ClientMapper, Client> impleme
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getClientByInternalCode(String code) {
|
public String getClientIdByCode(String code) {
|
||||||
return clientMapper.getClientByInternalCode(code);
|
return clientMapper.getClientIdByCode(code);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,25 +3,32 @@ package org.jeecg.modules.business.service.impl;
|
||||||
import freemarker.cache.FileTemplateLoader;
|
import freemarker.cache.FileTemplateLoader;
|
||||||
import freemarker.cache.TemplateLoader;
|
import freemarker.cache.TemplateLoader;
|
||||||
import freemarker.template.Configuration;
|
import freemarker.template.Configuration;
|
||||||
|
import freemarker.template.Template;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.jeecg.modules.business.service.EmailService;
|
import org.jeecg.modules.business.service.EmailService;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.core.env.Environment;
|
import org.springframework.core.env.Environment;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
|
||||||
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;
|
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;
|
||||||
|
|
||||||
import javax.mail.*;
|
import javax.mail.*;
|
||||||
import javax.mail.internet.*;
|
import javax.mail.internet.*;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
public class EmailServiceImpl implements EmailService {
|
public class EmailServiceImpl implements EmailService {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
Environment env;
|
Environment env;
|
||||||
|
@Autowired
|
||||||
|
FreeMarkerConfigurer freemarkerConfigurer;
|
||||||
@Override
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
public Properties getMailSender() {
|
public Properties getMailSender() {
|
||||||
|
|
@ -49,6 +56,41 @@ public class EmailServiceImpl implements EmailService {
|
||||||
|
|
||||||
Transport.send(message);
|
Transport.send(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public void newSendSimpleMessage(String recipient, String subject, String templateName, Map<String, Object> 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
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
public void sendMessageWithAttachment(String recipient, String subject, String text, String attachment, Session session) throws MessagingException, IOException {
|
public void sendMessageWithAttachment(String recipient, String subject, String text, String attachment, Session session) throws MessagingException, IOException {
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
|
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.jeecg.modules.business.controller.UserException;
|
||||||
import org.jeecg.modules.business.entity.*;
|
import org.jeecg.modules.business.entity.*;
|
||||||
import org.jeecg.modules.business.mapper.ExchangeRatesMapper;
|
import org.jeecg.modules.business.mapper.ExchangeRatesMapper;
|
||||||
import org.jeecg.modules.business.mapper.PlatformOrderContentMapper;
|
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.IPlatformOrderService;
|
||||||
import org.jeecg.modules.business.service.IShippingFeesWaiverProductService;
|
import org.jeecg.modules.business.service.IShippingFeesWaiverProductService;
|
||||||
import org.jeecg.modules.business.vo.PlatformOrderQuantity;
|
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.SkuQuantity;
|
||||||
import org.jeecg.modules.business.vo.SkuShippingFeesWaiver;
|
import org.jeecg.modules.business.vo.SkuShippingFeesWaiver;
|
||||||
import org.jeecg.modules.business.vo.clientPlatformOrder.ClientPlatformOrderPage;
|
import org.jeecg.modules.business.vo.clientPlatformOrder.ClientPlatformOrderPage;
|
||||||
|
|
@ -182,7 +184,7 @@ public class PlatformOrderServiceImpl extends ServiceImpl<PlatformOrderMapper, P
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public OrdersStatisticData getPlatformOrdersStatisticData(List<String> orderIds) {
|
public OrdersStatisticData getPlatformOrdersStatisticData(List<String> orderIds) throws UserException {
|
||||||
List<SkuQuantity> skuIDQuantityMap = platformOrderContentMap.searchOrderContent(orderIds);
|
List<SkuQuantity> skuIDQuantityMap = platformOrderContentMap.searchOrderContent(orderIds);
|
||||||
List<OrderContentDetail> data = searchPurchaseOrderDetail(skuIDQuantityMap);
|
List<OrderContentDetail> data = searchPurchaseOrderDetail(skuIDQuantityMap);
|
||||||
return OrdersStatisticData.makeData(data, null);
|
return OrdersStatisticData.makeData(data, null);
|
||||||
|
|
@ -200,14 +202,14 @@ public class PlatformOrderServiceImpl extends ServiceImpl<PlatformOrderMapper, P
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PurchaseConfirmation confirmPurchaseByPlatformOrder(List<String> platformOrderIdList) {
|
public PurchaseConfirmation confirmPurchaseByPlatformOrder(List<String> platformOrderIdList) throws UserException {
|
||||||
List<SkuQuantity> skuIDQuantityMap = platformOrderContentMap.searchOrderContent(platformOrderIdList);
|
List<SkuQuantity> skuIDQuantityMap = platformOrderContentMap.searchOrderContent(platformOrderIdList);
|
||||||
return confirmPurchaseBySkuQuantity(skuIDQuantityMap);
|
return confirmPurchaseBySkuQuantity(skuIDQuantityMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PurchaseConfirmation confirmPurchaseBySkuQuantity(List<SkuQuantity> skuIDQuantityMap) {
|
public PurchaseConfirmation confirmPurchaseBySkuQuantity(List<SkuQuantity> skuIDQuantityMap) throws UserException {
|
||||||
Client client = clientService.getCurrentClient();
|
Client client = clientService.getCurrentClient();
|
||||||
ClientInfo clientInfo = new ClientInfo(client);
|
ClientInfo clientInfo = new ClientInfo(client);
|
||||||
return new PurchaseConfirmation(clientInfo, searchPurchaseOrderDetail(skuIDQuantityMap),
|
return new PurchaseConfirmation(clientInfo, searchPurchaseOrderDetail(skuIDQuantityMap),
|
||||||
|
|
@ -215,13 +217,13 @@ public class PlatformOrderServiceImpl extends ServiceImpl<PlatformOrderMapper, P
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PurchaseConfirmation confirmPurchaseBySkuQuantity(ClientInfo clientInfo, List<SkuQuantity> skuIDQuantityMap) {
|
public PurchaseConfirmation confirmPurchaseBySkuQuantity(ClientInfo clientInfo, List<SkuQuantity> skuIDQuantityMap) throws UserException {
|
||||||
return new PurchaseConfirmation(clientInfo, searchPurchaseOrderDetail(skuIDQuantityMap),
|
return new PurchaseConfirmation(clientInfo, searchPurchaseOrderDetail(skuIDQuantityMap),
|
||||||
getShippingFeesWaiverMap(skuIDQuantityMap.stream().map(SkuQuantity::getID).collect(toList())));
|
getShippingFeesWaiverMap(skuIDQuantityMap.stream().map(SkuQuantity::getID).collect(toList())));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<OrderContentDetail> searchPurchaseOrderDetail(List<SkuQuantity> skuQuantities) {
|
public List<OrderContentDetail> searchPurchaseOrderDetail(List<SkuQuantity> skuQuantities) throws UserException {
|
||||||
BigDecimal eurToRmb = exchangeRatesMapper.getLatestExchangeRate("EUR", "RMB");
|
BigDecimal eurToRmb = exchangeRatesMapper.getLatestExchangeRate("EUR", "RMB");
|
||||||
// convert list of (ID, quantity) to map between ID and quantity
|
// convert list of (ID, quantity) to map between ID and quantity
|
||||||
Map<String, Integer> skuQuantity =
|
Map<String, Integer> skuQuantity =
|
||||||
|
|
@ -236,7 +238,14 @@ public class PlatformOrderServiceImpl extends ServiceImpl<PlatformOrderMapper, P
|
||||||
// Get list of sku ID
|
// Get list of sku ID
|
||||||
List<String> skuList = new ArrayList<>(skuQuantity.keySet());
|
List<String> skuList = new ArrayList<>(skuQuantity.keySet());
|
||||||
|
|
||||||
List<OrderContentDetail> details = platformOrderContentMap.searchSkuDetail(skuList).stream()
|
List<SkuDetail> 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<OrderContentDetail> details = skuDetails.stream()
|
||||||
.map(
|
.map(
|
||||||
skuDetail -> new OrderContentDetail(
|
skuDetail -> new OrderContentDetail(
|
||||||
skuDetail,
|
skuDetail,
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,7 @@ package org.jeecg.modules.business.service.impl;
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.jeecg.modules.business.entity.Client;
|
import org.jeecg.modules.business.entity.*;
|
||||||
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.mapper.ShippingInvoiceMapper;
|
import org.jeecg.modules.business.mapper.ShippingInvoiceMapper;
|
||||||
import org.jeecg.modules.business.service.IShippingInvoiceService;
|
import org.jeecg.modules.business.service.IShippingInvoiceService;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
|
@ -70,6 +67,11 @@ public class ShippingInvoiceServiceImpl extends ServiceImpl<ShippingInvoiceMappe
|
||||||
return shippingInvoiceMapper.fetchShopOwnerFromInvoiceNumber(invoiceNumber);
|
return shippingInvoiceMapper.fetchShopOwnerFromInvoiceNumber(invoiceNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Currency getInvoiceCurrencyByCode(String invoiceCode) {
|
||||||
|
return shippingInvoiceMapper.fetchInvoiceCurrencyByCode(invoiceCode);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
public String getShippingInvoiceId(String invoiceNumber) {
|
public String getShippingInvoiceId(String invoiceNumber) {
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ package org.jeecg.modules.business.service.impl.purchase;
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import org.jeecg.modules.business.controller.UserException;
|
||||||
import org.jeecg.modules.business.domain.codeGeneration.PurchaseInvoiceCodeRule;
|
import org.jeecg.modules.business.domain.codeGeneration.PurchaseInvoiceCodeRule;
|
||||||
import org.jeecg.modules.business.domain.purchase.invoice.InvoiceData;
|
import org.jeecg.modules.business.domain.purchase.invoice.InvoiceData;
|
||||||
import org.jeecg.modules.business.domain.purchase.invoice.PurchaseInvoice;
|
import org.jeecg.modules.business.domain.purchase.invoice.PurchaseInvoice;
|
||||||
|
|
@ -212,7 +213,7 @@ public class PurchaseOrderServiceImpl extends ServiceImpl<PurchaseOrderMapper, P
|
||||||
* @return the purchase order's identifier (UUID)
|
* @return the purchase order's identifier (UUID)
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String addPurchase(List<SkuQuantity> skuQuantities) {
|
public String addPurchase(List<SkuQuantity> skuQuantities) throws UserException {
|
||||||
return addPurchase(skuQuantities, Collections.emptyList());
|
return addPurchase(skuQuantities, Collections.emptyList());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -228,7 +229,7 @@ public class PurchaseOrderServiceImpl extends ServiceImpl<PurchaseOrderMapper, P
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
public String addPurchase(List<SkuQuantity> skuQuantities, List<String> platformOrderIDs) {
|
public String addPurchase(List<SkuQuantity> skuQuantities, List<String> platformOrderIDs) throws UserException {
|
||||||
Objects.requireNonNull(platformOrderIDs);
|
Objects.requireNonNull(platformOrderIDs);
|
||||||
|
|
||||||
Client client = clientService.getCurrentClient();
|
Client client = clientService.getCurrentClient();
|
||||||
|
|
@ -318,7 +319,7 @@ public class PurchaseOrderServiceImpl extends ServiceImpl<PurchaseOrderMapper, P
|
||||||
@Override
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
public String addPurchase(String username, Client client, String invoiceNumber, List<SkuQuantity> skuQuantities,
|
public String addPurchase(String username, Client client, String invoiceNumber, List<SkuQuantity> skuQuantities,
|
||||||
Map<PlatformOrder, List<PlatformOrderContent>> orderAndContent) {
|
Map<PlatformOrder, List<PlatformOrderContent>> orderAndContent) throws UserException {
|
||||||
Objects.requireNonNull(orderAndContent);
|
Objects.requireNonNull(orderAndContent);
|
||||||
|
|
||||||
List<OrderContentDetail> details = platformOrderService.searchPurchaseOrderDetail(skuQuantities);
|
List<OrderContentDetail> details = platformOrderService.searchPurchaseOrderDetail(skuQuantities);
|
||||||
|
|
@ -470,4 +471,19 @@ public class PurchaseOrderServiceImpl extends ServiceImpl<PurchaseOrderMapper, P
|
||||||
Path invoice = Paths.get(INVOICE_DIR, invoiceCode + ".xlsx");
|
Path invoice = Paths.get(INVOICE_DIR, invoiceCode + ".xlsx");
|
||||||
return Files.readAllBytes(invoice);
|
return Files.readAllBytes(invoice);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BigDecimal getPurchaseFeesByInvoiceCode(String invoiceCode) {
|
||||||
|
return purchaseOrderMapper.getPurchaseFeesByInvoiceCode(invoiceCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cancelInvoice(String invoiceNumber) {
|
||||||
|
purchaseOrderMapper.deleteInvoice(invoiceNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cancelBatchInvoice(List<String> invoiceNumbers) {
|
||||||
|
purchaseOrderMapper.deleteBatchInvoice(invoiceNumbers);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
@ -1,16 +1,18 @@
|
||||||
package org.jeecg.modules.business.vo;
|
package org.jeecg.modules.business.vo;
|
||||||
|
|
||||||
import com.alibaba.fastjson.annotation.JSONField;
|
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@Data
|
||||||
public class ShippingInvoiceParam {
|
public class ShippingInvoiceParam {
|
||||||
|
|
||||||
private final String clientID;
|
private final String clientID;
|
||||||
|
private final BigDecimal balance;
|
||||||
private final List<String> shopIDs;
|
private final List<String> shopIDs;
|
||||||
private final String start;
|
private final String start;
|
||||||
private final String end;
|
private final String end;
|
||||||
|
|
@ -19,12 +21,14 @@ public class ShippingInvoiceParam {
|
||||||
private final static SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
|
private final static SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
|
||||||
|
|
||||||
public ShippingInvoiceParam(@JsonProperty("clientID") String clientID,
|
public ShippingInvoiceParam(@JsonProperty("clientID") String clientID,
|
||||||
|
@JsonProperty("balance") BigDecimal balance,
|
||||||
@JsonProperty("shopIDs") List<String> shopIDs,
|
@JsonProperty("shopIDs") List<String> shopIDs,
|
||||||
@JsonProperty("start") String start,
|
@JsonProperty("start") String start,
|
||||||
@JsonProperty("end") String end,
|
@JsonProperty("end") String end,
|
||||||
@JsonProperty("erpStatuses") List<Integer> erpStatuses,
|
@JsonProperty("erpStatuses") List<Integer> erpStatuses,
|
||||||
@JsonProperty("warehouses") List<String> warehouses) {
|
@JsonProperty("warehouses") List<String> warehouses) {
|
||||||
this.clientID = clientID;
|
this.clientID = clientID;
|
||||||
|
this.balance = balance;
|
||||||
this.shopIDs = shopIDs;
|
this.shopIDs = shopIDs;
|
||||||
this.start = start;
|
this.start = start;
|
||||||
this.end = end;
|
this.end = end;
|
||||||
|
|
@ -47,16 +51,6 @@ public class ShippingInvoiceParam {
|
||||||
public Date end() throws ParseException {
|
public Date end() throws ParseException {
|
||||||
return format.parse(end);
|
return format.parse(end);
|
||||||
}
|
}
|
||||||
public String getStart() {
|
|
||||||
return this.start;
|
|
||||||
}
|
|
||||||
public String getEnd() {
|
|
||||||
return this.end;
|
|
||||||
}
|
|
||||||
public List<Integer> getErpStatuses() { return erpStatuses; }
|
|
||||||
public List<String> getWarehouses() {
|
|
||||||
return warehouses;
|
|
||||||
}
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "ShippingInvoiceParam{" + clientID +
|
return "ShippingInvoiceParam{" + clientID +
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,4 @@
|
||||||
<!DOCTYPE html>
|
<#include "components/header.ftl">
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<table align="center" cellpadding="0" cellspacing="0" width="600" bgcolor="#FFF" style="font-family:Arial,Helvetica,sans-serif;text-align:center;table-layout:fixed;font-size: 16px;border: 1px solid #0B49A6">
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td width="600" height="90" bgcolor="#0B49A6" valign="top" align="center" style="padding:20px 0;table-layout:fixed">
|
|
||||||
<a href="http://app.wia-sourcing.com/user/login">
|
|
||||||
<img src="https://wia-sourcing.com/wp-content/uploads/2022/10/Fichier-24Icons.png" alt="logo" width="360" style="width:100%;max-width:360px;">
|
|
||||||
</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="left">
|
|
||||||
<table width="520" align="center" style="color:#000;">
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
<tr>
|
||||||
<td style="padding:35px 0;">Cher collègue,</td>
|
<td style="padding:35px 0;">Cher collègue,</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
@ -37,62 +19,4 @@
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</#list>
|
</#list>
|
||||||
<tr>
|
<#include "components/footer.ftl">
|
||||||
<td style="padding:35px 0 5px 0;">Merci d’utiliser nos services.</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td style="padding:5px 0;">Cordialement</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td style="padding:5px 0 35px 0;">L’équipe WIA Sourcing.</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="left" bgcolor="#0B49A6" width="600">
|
|
||||||
<table align="center" width="520">
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td style="font-style: italic;padding: 20px 0;">Ce message a été envoyé automatiquement. Merci de ne pas répondre. Ce message et ainsi que toutes les pièces jointes sont confidentielles.</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td style="padding: 0 0 20px 0;">Si vous avez reçu ce message par erreur, merci de nous avertir immédiatement et de détruire ce message.</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>Service client :</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>Pour obtenir plus d’informations concernant nos services, veuillez nous contacter à l’adresse ci-dessous ou en visitant notre site web.</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<table align="center" width="520" style="padding: 15px 0">
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td width="220" style="text-align:center;border-radius:2em;padding:20px 10px 20px 0;;" bgcolor="#EF5A1A"><a href="https://wia-sourcing.com/contactez-nous" style="color:white;text-decoration:none">Nous contacter</a></td>
|
|
||||||
<td width="40" ></td>
|
|
||||||
<td width="220" style="text-align:center;border-radius:2em;padding:20px 0 20px 10px;" bgcolor="#EF5A1A"><a href="https://wia-sourcing.com/" style="color:white;text-decoration:none">Notre site web</a></td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<table align="center" width="520" style="padding: 0 0 35px 0;">
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td style="color:#EF5A1A;">WIA SOURCING</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>© 2018/2023 par WIA Sourcing Agency.</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>TOUS DROITS RÉSERVÉS©</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -0,0 +1,56 @@
|
||||||
|
<#include "../components/header.ftl">
|
||||||
|
<tr>
|
||||||
|
<td style="padding:35px 0;">Cher(e) ${client.firstName} ${client.surname},</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td style="padding:0 0 35px 0;">Une ou plusieurs commandes n'ont pas pu être facturées en raison d'un solde insuffisant :</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<#if errors?size = 0>
|
||||||
|
<p>No error</p>
|
||||||
|
<#elseif chronologicalOrder=="1">
|
||||||
|
<p>Les commandes à partir du numéro ${errors[0].platformOrderNumber} - ${errors[0].orderTime?datetime?string('dd-MM-yyyy')} n'ont pas été facturées.</p>
|
||||||
|
<#else>
|
||||||
|
<table style="border: 1px solid #bbb; text-align: center;width: 100%">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Numéro de commande</th>
|
||||||
|
<th>Date de commande</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<#list errors as error>
|
||||||
|
<tr>
|
||||||
|
<td>${error.platformOrderNumber}</td>
|
||||||
|
<td>${error.orderTime?datetime?string('dd-MM-yyyy')}</td>
|
||||||
|
</tr>
|
||||||
|
</#list>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</#if>
|
||||||
|
<#if skipped??>
|
||||||
|
<table style="border: 1px solid #bbb; text-align: center;width: 100%">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Numéro de commande</th>
|
||||||
|
<th>Date de commande</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<#list skipped as error>
|
||||||
|
<tr>
|
||||||
|
<td>${error.platformOrderNumber}</td>
|
||||||
|
<td>${error.orderTime?datetime?string('dd-MM-yyyy')}</td>
|
||||||
|
</tr>
|
||||||
|
</#list>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</#if>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td style="padding:0 0 35px 0;">Pour continuer à utiliser nos services, nous vous invitons à recharger votre compte.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td style="padding:0 0 35px 0;">Pour toute information complémentaire nous vous invitons à vous rapprocher de votre conseiller.</td>
|
||||||
|
</tr>
|
||||||
|
<#include "../components/footer.ftl">
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
<#include "../components/header.ftl">
|
||||||
|
<tr>
|
||||||
|
<td style="padding:35px 0;">Cher(e) ${firstname} ${lastname},</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td style="padding:0 0 35px 0;">Vous recevez cet e-mail car votre solde sur la plateforme de WIA App est actuellement de <b>${balance} ${currency}</b></td>
|
||||||
|
</tr>
|
||||||
|
<#if clientCategory != "vip">
|
||||||
|
<tr>
|
||||||
|
<td style="padding:0 0 35px 0;">Pour continuer à utiliser nos services, nous vous invitons à recharger votre compte.</td>
|
||||||
|
</tr>
|
||||||
|
</#if>
|
||||||
|
<tr>
|
||||||
|
<td style="padding:0 0 35px 0;">Pour toute information complémentaire nous vous invitons à vous rapprocher de votre conseiller.</td>
|
||||||
|
</tr>
|
||||||
|
<#include "../components/footer.ftl">
|
||||||
|
|
@ -0,0 +1,59 @@
|
||||||
|
<tr>
|
||||||
|
<td style="padding:35px 0 5px 0;">Merci d’utiliser nos services.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td style="padding:5px 0;">Cordialement</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td style="padding:5px 0 35px 0;">L’équipe WIA Sourcing.</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="left" bgcolor="#0B49A6" width="600" style="padding: 20px 0;">
|
||||||
|
<#-- <table align="center" width="520" style="padding: 15px 0">-->
|
||||||
|
<#-- <tbody>-->
|
||||||
|
<#-- <tr>-->
|
||||||
|
<#-- <td width="220" style="text-align:center;border-radius:2em;padding:20px 10px 20px 0;;" bgcolor="#EF5A1A"><a href="https://wia-sourcing.com/contactez-nous" style="color:white;text-decoration:none">Nous contacter</a></td>-->
|
||||||
|
<#-- <td width="40" ></td>-->
|
||||||
|
<#-- <td width="220" style="text-align:center;border-radius:2em;padding:20px 0 20px 10px;" bgcolor="#EF5A1A"><a href="https://wia-sourcing.com/" style="color:white;text-decoration:none">Notre site web</a></td>-->
|
||||||
|
<#-- </tr>-->
|
||||||
|
<#-- </tbody>-->
|
||||||
|
<#-- </table>-->
|
||||||
|
<table align="center" width="520">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td style="color:#EF5A1A;">WIA SOURCING</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>© 2018/2023 par WIA Sourcing Agency.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>TOUS DROITS RÉSERVÉS©</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<table align="center" width="520">
|
||||||
|
<tbody style="color: white; font-size: 12px;">
|
||||||
|
<tr>
|
||||||
|
<td style="font-style: italic;padding: 20px 0;">Ce message a été envoyé automatiquement. Merci de ne pas y répondre. <br/>Ce message et ainsi que toutes les pièces jointes sont confidentielles.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td style="padding: 0 0 20px 0;">Si vous avez reçu ce message par erreur, merci de nous en avertir immédiatement et de détruire ce message.</td>
|
||||||
|
</tr>
|
||||||
|
<#-- <tr>-->
|
||||||
|
<#-- <td>Service client :</td>-->
|
||||||
|
<#-- </tr>-->
|
||||||
|
<#-- <tr>-->
|
||||||
|
<#-- <td>Pour obtenir plus d’informations concernant nos services, veuillez nous contacter à l’adresse ci-dessous ou en visitant notre site web.</td>-->
|
||||||
|
<#-- </tr>-->
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<table align="center" cellpadding="0" cellspacing="0" width="600" bgcolor="#FFF" style="font-family:Arial,Helvetica,sans-serif;text-align:center;table-layout:fixed;font-size: 16px;border: 1px solid #0B49A6">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td width="600" height="90" bgcolor="#0B49A6" valign="top" align="center" style="padding:20px 0;table-layout:fixed">
|
||||||
|
<a href="http://app.wia-sourcing.com/user/login">
|
||||||
|
<img src="https://wia-sourcing.com/wp-content/uploads/2022/10/Fichier-24Icons.png" alt="logo" width="360" style="width:100%;max-width:360px;">
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="left">
|
||||||
|
<table width="520" align="center" style="color:#000;">
|
||||||
|
<tbody>
|
||||||
|
|
@ -1,22 +1,4 @@
|
||||||
<!DOCTYPE html>
|
<#include "components/header.ftl">
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<table align="center" cellpadding="0" cellspacing="0" width="600" bgcolor="#FFF" style="font-family:Arial,Helvetica,sans-serif;text-align:center;table-layout:fixed;font-size: 16px;border: 1px solid #0B49A6">
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td width="600" height="90" bgcolor="#0B49A6" valign="top" align="center" style="padding:20px 0;table-layout:fixed">
|
|
||||||
<a href="http://app.wia-sourcing.com/user/login">
|
|
||||||
<img src="https://wia-sourcing.com/wp-content/uploads/2022/10/Fichier-24Icons.png" alt="logo" width="360" style="width:100%;max-width:360px;">
|
|
||||||
</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="left">
|
|
||||||
<table width="520" align="center" style="color:#000;">
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
<tr>
|
||||||
<td style="padding:35px 0;">Cher Client(e),</td>
|
<td style="padding:35px 0;">Cher Client(e),</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
@ -32,62 +14,4 @@
|
||||||
<tr>
|
<tr>
|
||||||
<td style="padding:10px 0;"><b>Numéro de facture :</b> <a href="http://app.wia-sourcing.com/business/admin/shippingInvoice/Invoice?invoice=${invoiceNumber}"> ${invoiceNumber} </a></td>
|
<td style="padding:10px 0;"><b>Numéro de facture :</b> <a href="http://app.wia-sourcing.com/business/admin/shippingInvoice/Invoice?invoice=${invoiceNumber}"> ${invoiceNumber} </a></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<#include "components/footer.ftl">
|
||||||
<td style="padding:35px 0 5px 0;">Merci d’utiliser nos services.</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td style="padding:5px 0;">Cordialement</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td style="padding:5px 0 35px 0;">L’équipe WIA Sourcing.</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="left" bgcolor="#0B49A6" width="600">
|
|
||||||
<table align="center" width="520">
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td style="font-style: italic;padding: 20px 0;">Ce message a été envoyé automatiquement. Merci de ne pas répondre. Ce message et ainsi que toutes les pièces jointes sont confidentielles.</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td style="padding: 0 0 20px 0;">Si vous avez reçu ce message par erreur, merci de nous avertir immédiatement et de détruire ce message.</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>Service client :</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>Pour obtenir plus d’informations concernant nos services, veuillez nous contacter à l’adresse ci-dessous ou en visitant notre site web.</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<table align="center" width="520" style="padding: 15px 0">
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td width="220" style="text-align:center;border-radius:2em;padding:20px 10px 20px 0;;" bgcolor="#EF5A1A"><a href="https://wia-sourcing.com/contactez-nous" style="color:white;text-decoration:none">Nous contacter</a></td>
|
|
||||||
<td width="40" ></td>
|
|
||||||
<td width="220" style="text-align:center;border-radius:2em;padding:20px 0 20px 10px;" bgcolor="#EF5A1A"><a href="https://wia-sourcing.com/" style="color:white;text-decoration:none">Notre site web</a></td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<table align="center" width="520" style="padding: 0 0 35px 0;">
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td style="color:#EF5A1A;">WIA SOURCING</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>© 2018/2023 par WIA Sourcing Agency.</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>TOUS DROITS RÉSERVÉS©</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</body>
|
|
||||||
</html>"
|
|
||||||
|
|
@ -1,22 +1,4 @@
|
||||||
<!DOCTYPE html>
|
<#include "components/header.ftl">
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<table align="center" cellpadding="0" cellspacing="0" width="600" bgcolor="#FFF" style="font-family:Arial,Helvetica,sans-serif;text-align:center;table-layout:fixed;font-size: 16px;border: 1px solid #0B49A6">
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td width="600" height="90" bgcolor="#0B49A6" valign="top" align="center" style="padding:20px 0;table-layout:fixed">
|
|
||||||
<a href="http://app.wia-sourcing.com/user/login">
|
|
||||||
<img src="https://wia-sourcing.com/wp-content/uploads/2022/10/Fichier-24Icons.png" alt="logo" width="360" style="width:100%;max-width:360px;">
|
|
||||||
</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="left">
|
|
||||||
<table width="520" align="center" style="color:#000;">
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
<tr>
|
||||||
<td style="padding:35px 0;">Cher(s) collègue(s),</td>
|
<td style="padding:35px 0;">Cher(s) collègue(s),</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
@ -52,62 +34,4 @@
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<#include "components/footer.ftl">
|
||||||
<td style="padding:35px 0 5px 0;">Merci d’utiliser nos services.</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td style="padding:5px 0;">Cordialement</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td style="padding:5px 0 35px 0;">L’équipe WIA Sourcing.</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="left" bgcolor="#0B49A6" width="600">
|
|
||||||
<table align="center" width="520">
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td style="font-style: italic;padding: 20px 0;">Ce message a été envoyé automatiquement. Merci de ne pas répondre. Ce message et ainsi que toutes les pièces jointes sont confidentielles.</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td style="padding: 0 0 20px 0;">Si vous avez reçu ce message par erreur, merci de nous avertir immédiatement et de détruire ce message.</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>Service client :</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>Pour obtenir plus d’informations concernant nos services, veuillez nous contacter à l’adresse ci-dessous ou en visitant notre site web.</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<table align="center" width="520" style="padding: 15px 0">
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td width="220" style="text-align:center;border-radius:2em;padding:20px 10px 20px 0;;" bgcolor="#EF5A1A"><a href="https://wia-sourcing.com/contactez-nous" style="color:white;text-decoration:none">Nous contacter</a></td>
|
|
||||||
<td width="40" ></td>
|
|
||||||
<td width="220" style="text-align:center;border-radius:2em;padding:20px 0 20px 10px;" bgcolor="#EF5A1A"><a href="https://wia-sourcing.com/" style="color:white;text-decoration:none">Notre site web</a></td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<table align="center" width="520" style="padding: 0 0 35px 0;">
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td style="color:#EF5A1A;">WIA SOURCING</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>© 2018/2023 par WIA Sourcing Agency.</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>TOUS DROITS RÉSERVÉS©</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,27 +1,9 @@
|
||||||
<!DOCTYPE html>
|
<#include "components/header.ftl">
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<table align="center" cellpadding="0" cellspacing="0" width="600" bgcolor="#FFF" style="font-family:Arial,Helvetica,sans-serif;text-align:center;table-layout:fixed;font-size: 16px;border: 1px solid #0B49A6">
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td width="600" height="90" bgcolor="#0B49A6" valign="top" align="center" style="padding:20px 0;table-layout:fixed">
|
|
||||||
<a href="http://app.wia-sourcing.com/user/login">
|
|
||||||
<img src="https://wia-sourcing.com/wp-content/uploads/2022/10/Fichier-24Icons.png" alt="logo" width="360" style="width:100%;max-width:360px;">
|
|
||||||
</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="left">
|
|
||||||
<table width="520" align="center" style="color:#000;">
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
<tr>
|
||||||
<td style="padding:35px 0;">Cher(s) collègue(s),</td>
|
<td style="padding:35px 0;">Cher(s) collègue(s),</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td style="padding:0 0 35px 0;">Des erreurs se sont produites lors du déroulement de la tâche plannifiée : <b>VIP invoicing job</b></td>
|
<td style="padding:0 0 35px 0;">Des erreurs se sont produites lors du déroulement de la tâche plannifiée suivante : <br/><b>${job} invoicing job</b></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td style="padding:10px 0;"><b>Erreurs :</b>
|
<td style="padding:10px 0;"><b>Erreurs :</b>
|
||||||
|
|
@ -31,79 +13,21 @@
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<table style="border: 1px solid #bbb; text-align: center;">
|
<table style="border: 1px solid #bbb; border-collapse: collapse; text-align: center; width: 100%;">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Client</th>
|
<th style="border: 1px solid #bbb;">Client</th>
|
||||||
<th>Error Message</th>
|
<th style="border: 1px solid #bbb;">Error Message</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<#list errors as error>
|
<#list errors as error>
|
||||||
<tr>
|
<tr>
|
||||||
<td>${error.internalCode}</td>
|
<td style="border: 1px solid #bbb;">${error.internalCode}</td>
|
||||||
<td>${error.errorMsg}</td>
|
<td style="border: 1px solid #bbb;">${error.errorMsg}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</#list>
|
</#list>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<#include "components/footer.ftl">
|
||||||
<td style="padding:35px 0 5px 0;">Merci d’utiliser nos services.</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td style="padding:5px 0;">Cordialement</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td style="padding:5px 0 35px 0;">L’équipe WIA Sourcing.</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="left" bgcolor="#0B49A6" width="600">
|
|
||||||
<table align="center" width="520">
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td style="font-style: italic;padding: 20px 0;">Ce message a été envoyé automatiquement. Merci de ne pas répondre. Ce message et ainsi que toutes les pièces jointes sont confidentielles.</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td style="padding: 0 0 20px 0;">Si vous avez reçu ce message par erreur, merci de nous avertir immédiatement et de détruire ce message.</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>Service client :</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>Pour obtenir plus d’informations concernant nos services, veuillez nous contacter à l’adresse ci-dessous ou en visitant notre site web.</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<table align="center" width="520" style="padding: 15px 0">
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td width="220" style="text-align:center;border-radius:2em;padding:20px 10px 20px 0;;" bgcolor="#EF5A1A"><a href="https://wia-sourcing.com/contactez-nous" style="color:white;text-decoration:none">Nous contacter</a></td>
|
|
||||||
<td width="40" ></td>
|
|
||||||
<td width="220" style="text-align:center;border-radius:2em;padding:20px 0 20px 10px;" bgcolor="#EF5A1A"><a href="https://wia-sourcing.com/" style="color:white;text-decoration:none">Notre site web</a></td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<table align="center" width="520" style="padding: 0 0 35px 0;">
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td style="color:#EF5A1A;">WIA SOURCING</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>© 2018/2023 par WIA Sourcing Agency.</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>TOUS DROITS RÉSERVÉS©</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
Loading…
Reference in New Issue