diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/controller/admin/SkuController.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/controller/admin/SkuController.java index 39c7ecc5a..0397fe0cc 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/controller/admin/SkuController.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/controller/admin/SkuController.java @@ -8,6 +8,7 @@ import freemarker.template.Template; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import lombok.extern.slf4j.Slf4j; +import org.apache.http.HttpStatus; import org.apache.shiro.SecurityUtils; import org.jeecg.common.api.vo.Result; import org.jeecg.common.aspect.annotation.AutoLog; @@ -58,6 +59,8 @@ import static org.jeecg.common.util.SqlInjectionUtil.specialFilterContentForDict @RequestMapping("/sku") @Slf4j public class SkuController { + @Autowired + private IClientService clientService; @Autowired private IShopService shopService; @Autowired @@ -75,6 +78,8 @@ public class SkuController { @Autowired private SkuMongoService skuMongoService; @Autowired + private ISecurityService securityService; + @Autowired private EmailService emailService; @Autowired private FreeMarkerConfigurer freemarkerConfigurer; @@ -380,6 +385,19 @@ public class SkuController { @RequestParam(name = "zhNames", required = false) String zhNames, @RequestParam(name = "enNames", required = false) String enNames, ServletRequest servletRequest) { + if(!securityService.checkIsEmployee()) { + Client client = clientService.getCurrentClient(); + // Here we don't explicitly tell the user that they are not allowed to access this endpoint for security measure. + if (client == null) { + return Result.error(HttpStatus.SC_NOT_FOUND, "Profile not found"); + } + if( clientId == null) { + return Result.error(HttpStatus.SC_BAD_REQUEST, "Bad request"); + } + if(!client.getId().equals(clientId)) { + return Result.error(HttpStatus.SC_NOT_FOUND, "Client not found"); + } + } String parsedColumn = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, column.replace("_dictText", "")); String parsedOrder = order.toUpperCase(); if(!parsedOrder.equals("ASC") && !parsedOrder.equals("DESC")) { diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/controller/admin/shippingInvoice/InvoiceController.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/controller/admin/shippingInvoice/InvoiceController.java index 3fb9aef5b..dc81e1739 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/controller/admin/shippingInvoice/InvoiceController.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/controller/admin/shippingInvoice/InvoiceController.java @@ -10,6 +10,7 @@ import freemarker.template.Template; import freemarker.template.TemplateException; import io.swagger.annotations.Api; import lombok.extern.slf4j.Slf4j; +import org.apache.http.HttpStatus; import org.apache.shiro.SecurityUtils; import org.jeecg.common.api.vo.Result; import org.jeecg.common.system.query.QueryGenerator; @@ -76,6 +77,8 @@ public class InvoiceController { @Autowired private IClientService clientService; @Autowired + private IClientSkuService clientSkuService; + @Autowired private ICurrencyService currencyService; @Autowired private ExchangeRatesMapper exchangeRatesMapper; @@ -383,12 +386,12 @@ public class InvoiceController { */ @Transactional @PostMapping(value = "/makeManualComplete") - public Result makeManualCompleteInvoice(@RequestBody ShippingInvoiceOrderParam param) { + public Result makeManualCompleteInvoice(@RequestBody ManualInvoiceOrderParam param) { try { - InvoiceMetaData metaData = shippingInvoiceService.makeCompleteInvoice(param); - String clientCategory = clientCategoryService.getClientCategoryByClientId(param.clientID()); + InvoiceMetaData metaData = shippingInvoiceService.makeManualCompleteInvoice(param); + String clientCategory = clientCategoryService.getClientCategoryByClientId(param.getClientID()); if(clientCategory.equals(ClientCategory.CategoryName.CONFIRMED.getName()) || clientCategory.equals(ClientCategory.CategoryName.VIP.getName())) { - balanceService.updateBalance(param.clientID(), metaData.getInvoiceCode(), COMPLETE.name()); + balanceService.updateBalance(param.getClientID(), metaData.getInvoiceCode(), COMPLETE.name()); } if(clientCategory.equals(ClientCategory.CategoryName.SELF_SERVICE.getName())) { String subject = "Self-service complete invoice"; @@ -396,7 +399,7 @@ public class InvoiceController { Properties prop = emailService.getMailSender(); Map templateModel = new HashMap<>(); templateModel.put("invoiceType", "complete invoice"); - templateModel.put("invoiceEntity", clientService.getById(param.clientID()).getInternalCode()); + templateModel.put("invoiceEntity", clientService.getById(param.getClientID()).getInternalCode()); templateModel.put("invoiceNumber", metaData.getInvoiceCode()); Session session = Session.getInstance(prop, new Authenticator() { @@ -423,10 +426,22 @@ public class InvoiceController { } @PostMapping("/makeManualSkuPurchaseInvoice") public Result createOrder(@RequestBody Map payload) { + boolean isEmployee = securityService.checkIsEmployee(); + Client client = null; + if(!isEmployee) { + client = clientService.getCurrentClient(); + if(client == null) + return Result.error(HttpStatus.SC_NOT_FOUND, "Client not found"); + } InvoiceMetaData metaData; List skuQuantities = new ArrayList<>(); for(Map.Entry entry : payload.entrySet()) { String skuId = skuService.getIdFromErpCode(entry.getKey()); + if(client != null) { + String skuClientId = clientSkuService.getClientIdFromSkuId(skuId); + if (!skuClientId.equals(client.getId())) + return Result.error(HttpStatus.SC_NOT_FOUND, "Sku " + entry.getKey() + " for client " + client.getInternalCode() + " not found."); + } skuQuantities.add(new SkuQuantity(skuId, entry.getKey(), entry.getValue())); } try { diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/shippingInvoice/ShippingInvoiceFactory.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/shippingInvoice/ShippingInvoiceFactory.java index 55e47aed8..565dee386 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/shippingInvoice/ShippingInvoiceFactory.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/shippingInvoice/ShippingInvoiceFactory.java @@ -42,6 +42,8 @@ import static org.jeecg.modules.business.entity.Invoice.InvoicingMethod.*; @Component public class ShippingInvoiceFactory { + @Autowired + private IClientService clientService; @Autowired private IExtraFeeService extraFeeService; @Autowired @@ -99,6 +101,7 @@ public class ShippingInvoiceFactory { return skuDeclaredValueService.getDeclaredValueForDate(skuIdAndDate.getLeft(), skuIdAndDate.getRight()); } }); + private final List CLIENT_STOCK_BYPASS_LIST = Arrays.asList("LA", "AP"); /** * Creates an invoice for a client according to type @@ -149,6 +152,7 @@ public class ShippingInvoiceFactory { /** * Creates a complete shipping (purchase + shipping) invoice for a client + * /!\ if the client is in the bypass list and ordersWithStock is not empty we only invoice the shipping fee of these orders, and we don't invoice the purchase fee *

* To generate an invoice, it *

    @@ -164,12 +168,13 @@ public class ShippingInvoiceFactory { * @param customerId the customer id * @param orderIds the list of order IDs * @param shippingMethod "post" = postShipping, "pre" = preShipping, "all" = all shipping methods + * @param ordersWithStock for orders with stock, if the client is in the bypass list, we only invoice the shipping fee and we don't invoice the purchase fee of the orders with stock * @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 createCompleteShippingInvoice(String username, String customerId, BigDecimal balance, List orderIds, String shippingMethod, String start, String end) throws UserException, MessagingException, InterruptedException { + public CompleteInvoice createCompleteShippingInvoice(String username, String customerId, BigDecimal balance, List orderIds, String shippingMethod, String start, String end, List ordersWithStock) throws UserException, MessagingException, InterruptedException { log.info("Creating a complete invoice for \n client ID: {}, order IDs: {}]", customerId, orderIds); // find orders and their contents of the invoice Map> uninvoicedOrderToContent = platformOrderService.fetchUninvoicedOrderDataForUpdate(orderIds); @@ -184,19 +189,32 @@ public class ShippingInvoiceFactory { .collect(Collectors.toList()); List extraFees = extraFeeService.findNotInvoicedByShops(shopIds); log.info("Orders to be invoiced: {}", uninvoicedOrderToContent); - String subject; - if(shippingMethod.equals("shipping")) - subject = String.format("Purchase and Shipping fees from %s to %s", start, end); - else if(shippingMethod.equals(POSTSHIPPING.getMethod())) - subject = String.format("Purchase and post-Shipping fees from %s to %s", start, end); - else if (shippingMethod.equals(PRESHIPPING.getMethod())) - subject = String.format("Purchase and pre-Shipping fees, order time from %s to %s", start, end); - else if(shippingMethod.equals(ALL.getMethod())) - subject = String.format("Purchase and Shipping fees, order time from %s to %s", start, end); + StringBuilder subject = new StringBuilder(); + boolean hasPeriod = start != null && !start.isEmpty() && end != null && !end.isEmpty(); + if(shippingMethod.equals("shipping")) { + subject.append("Purchase and Shipping fees"); + if(hasPeriod) + subject.append(String.format(" from %s to %s", start, end)); + } + else if(shippingMethod.equals(POSTSHIPPING.getMethod())) { + subject.append("Purchase and post-Shipping fees"); + if(hasPeriod) + subject.append(String.format(" from %s to %s", start, end)); + } + else if (shippingMethod.equals(PRESHIPPING.getMethod())) { + subject.append("Purchase and Pre-Shipping fees"); + if(hasPeriod) + subject.append(String.format(" order time from %s to %s", start, end)); + } + else if(shippingMethod.equals(ALL.getMethod())) { + subject.append("Purchase and Shipping fees"); + if(hasPeriod) + subject.append(String.format(" order time from %s to %s", start, end)); + } else throw new UserException("Couldn't create complete invoice for unknown shipping method"); if(balance != null) - return createCompleteInvoiceWithBalance(username, customerId, balance, shopIds, uninvoicedOrderToContent, savRefunds, extraFees, subject); - return createInvoice(username, customerId, null, shopIds, uninvoicedOrderToContent, savRefunds, extraFees, subject); + return createCompleteInvoiceWithBalance(username, customerId, balance, shopIds, uninvoicedOrderToContent, savRefunds, extraFees, subject.toString()); + return createInvoice(username, customerId, null, shopIds, uninvoicedOrderToContent, savRefunds, extraFees, subject.toString(), ordersWithStock); } @@ -225,7 +243,7 @@ public class ShippingInvoiceFactory { @Transactional public CompleteInvoice createInvoice(String username, String customerId, BigDecimal balance, List shopIds, Map> orderAndContent, - List savRefunds, List extraFees, String subject) throws UserException { + List savRefunds, List extraFees, String subject, List ordersWithStock) throws UserException { Client client = clientMapper.selectById(customerId); log.info("User {} is creating a complete invoice for customer {}", username, client.getInternalCode()); @@ -251,20 +269,29 @@ public class ShippingInvoiceFactory { log.info("New invoice code: {}", invoiceCode); calculateFees(balance, logisticChannelMap, orderAndContent, channelPriceMap, countryList, skuRealWeights, skuServiceFees, latestDeclaredValues, client, shopServiceFeeMap, shopPackageMatFeeMap, invoiceCode); + // Purchase fees BigDecimal eurToUsd = exchangeRatesMapper.getLatestExchangeRate("EUR", "USD"); List orderIds = orderAndContent.keySet().stream().map(PlatformOrder::getId).collect(toList()); - List skuQuantities = platformOrderContentService.searchOrderContent(orderIds); - - String purchaseID = purchaseOrderService.addPurchase(username, client, invoiceCode, skuQuantities, orderAndContent); - - List purchaseOrderSkuList = purchaseOrderContentMapper.selectInvoiceDataByID(purchaseID); - List promotionDetails = skuPromotionHistoryMapper.selectPromotionByPurchase(purchaseID); - if (savRefunds != null) { - updateSavRefundsInDb(savRefunds, invoiceCode); + List purchaseOrderSkuList = new ArrayList<>(); + List promotionDetails = new ArrayList<>(); + List clientsThatByPassStock = clientService.getClientsByCode(CLIENT_STOCK_BYPASS_LIST); + if(clientsThatByPassStock.contains(customerId) && ordersWithStock != null && !ordersWithStock.isEmpty()) { + orderIds = orderIds.stream().filter(orderId -> !ordersWithStock.contains(orderId)).collect(toList()); } - if(extraFees != null && !extraFees.isEmpty()) { - List extraFeesIds = extraFees.stream().map(ExtraFeeResult::getId).collect(toList()); - extraFeeService.updateInvoiceNumberByIds(extraFeesIds, invoiceCode); + if(!orderIds.isEmpty()){ + List skuQuantities = platformOrderContentService.searchOrderContent(orderIds); + + String purchaseID = purchaseOrderService.addPurchase(username, client, invoiceCode, skuQuantities, orderAndContent, ordersWithStock); + + purchaseOrderSkuList = purchaseOrderContentMapper.selectInvoiceDataByID(purchaseID); + promotionDetails = skuPromotionHistoryMapper.selectPromotionByPurchase(purchaseID); + if (savRefunds != null) { + updateSavRefundsInDb(savRefunds, invoiceCode); + } + if(extraFees != null && !extraFees.isEmpty()) { + List extraFeesIds = extraFees.stream().map(ExtraFeeResult::getId).collect(toList()); + extraFeeService.updateInvoiceNumberByIds(extraFeesIds, invoiceCode); + } } updateOrdersAndContentsInDb(orderAndContent); @@ -391,7 +418,7 @@ public class ShippingInvoiceFactory { List orderIds = orderAndContent.keySet().stream().map(PlatformOrder::getId).collect(toList()); List skuQuantities = platformOrderContentService.searchOrderContent(orderIds); - String purchaseID = purchaseOrderService.addPurchase(username, client, invoiceCode, skuQuantities, orderAndContent); + String purchaseID = purchaseOrderService.addPurchase(username, client, invoiceCode, skuQuantities, orderAndContent, null); List purchaseOrderSkuList = purchaseOrderContentMapper.selectInvoiceDataByID(purchaseID); List promotionDetails = skuPromotionHistoryMapper.selectPromotionByPurchase(purchaseID); diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/ClientMapper.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/ClientMapper.java index f8ae566f5..fc1120383 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/ClientMapper.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/ClientMapper.java @@ -38,4 +38,6 @@ public interface ClientMapper extends BaseMapper { Client getByShopId(@Param("shopId") String shopId); Client getClientFromCredit(@Param("invoiceNumber") String invoiceNumber); + + List getClientsByCode(@Param("codes") List clientCodes); } diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/ClientSkuMapper.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/ClientSkuMapper.java index 5952a2ad4..463b36fcd 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/ClientSkuMapper.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/ClientSkuMapper.java @@ -21,4 +21,6 @@ public interface ClientSkuMapper extends BaseMapper { List selectByMainId(@Param("mainId") String mainId); List getUnpairedSkus(); + + String getClientIdFromSkuId(@Param("skuId") String skuId); } diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/xml/ClientMapper.xml b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/xml/ClientMapper.xml index 248969880..d9dd27aed 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/xml/ClientMapper.xml +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/xml/ClientMapper.xml @@ -107,4 +107,13 @@ JOIN credit ON c.id = credit.client_id WHERE credit.invoice_number = #{invoiceNumber}; + \ No newline at end of file diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/xml/ClientSkuMapper.xml b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/xml/ClientSkuMapper.xml index 7377bc9bc..e93aeaf9c 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/xml/ClientSkuMapper.xml +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/xml/ClientSkuMapper.xml @@ -2,22 +2,28 @@ - - DELETE - FROM client_sku - WHERE - client_id = #{mainId} - - + + DELETE + FROM client_sku + WHERE + client_id = #{mainId} + - + + + + diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/xml/SkuMapper.xml b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/xml/SkuMapper.xml index 5666bbf25..23df4792d 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/xml/SkuMapper.xml +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/xml/SkuMapper.xml @@ -184,10 +184,18 @@ JOIN shop s ON po.shop_id = s.id JOIN client c ON s.owner_id = c.id WHERE c.id = #{clientId} + AND poc.create_time >= '2025-01-01 00:00:00' AND po.erp_status IN ('1','2') AND po.can_send = 1 AND poc.erp_status IN ('1','2') GROUP BY sku_id + ), latest_exchange_rate AS ( + SELECT rate + FROM exchange_rates + WHERE original_currency = 'EUR' AND target_currency = 'RMB' + ORDER BY create_time DESC LIMIT 1 + ), rmb_id AS ( + SELECT id FROM currency WHERE code = 'RMB' ) SELECT s.id, s.erp_code, @@ -196,31 +204,25 @@ s.purchasing_amount, s.available_amount, qtyInOrdersNotShipped.quantity as qtyInOrdersNotShipped, - s.available_amount + s.purchasing_amount - IF(qtyInOrdersNotShipped.quantity IS NULL, 0, qtyInOrdersNotShipped.quantity) as stock, + s.available_amount + s.purchasing_amount - COALESCE(qtyInOrdersNotShipped.quantity, 0) as stock, s.image_source, s.service_fee, - IF(sp.price_rmb IS NULL, sp.price, + IF(sp.currency_id = (SELECT id FROM rmb_id), ( ROUND( - sp.price_rmb / - (SELECT rate - FROM exchange_rates - WHERE original_currency = 'EUR' AND target_currency = 'RMB' - ORDER BY create_time DESC LIMIT 1) + sp.price / + (SELECT rate FROM latest_exchange_rate) ,2) - ) + ), sp.price ) as sku_price, sp.threshold as discount_moq, - IF(sp.price_rmb IS NULL, sp.discounted_price, + IF(sp.currency_id = (SELECT id FROM rmb_id), ( ROUND( - sp.discounted_price_rmb / - (SELECT rate - FROM exchange_rates - WHERE target_currency = 'EUR' AND original_currency = 'RMB' - ORDER BY create_time DESC LIMIT 1) + sp.discounted_price / + (SELECT rate FROM latest_exchange_rate) ,2) - ) + ),sp.discounted_price ) as discounted_price, s7.quantity as sales_last_week, s28.quantity as sales_four_weeks, @@ -337,6 +339,13 @@ AND po.can_send = 1 AND poc.erp_status IN ('1','2') GROUP BY sku_id + ), latest_exchange_rate AS ( + SELECT rate + FROM exchange_rates + WHERE original_currency = 'EUR' AND target_currency = 'RMB' + ORDER BY create_time DESC LIMIT 1 + ), rmb_id AS ( + SELECT id FROM currency WHERE code = 'RMB' ) SELECT s.id, s.erp_code, @@ -345,31 +354,25 @@ s.purchasing_amount, s.available_amount, qtyInOrdersNotShippedCTE.quantity as qtyInOrdersNotShipped, - s.available_amount + s.purchasing_amount - IF(qtyInOrdersNotShippedCTE.quantity IS NULL, 0, qtyInOrdersNotShippedCTE.quantity) as stock, + s.available_amount + s.purchasing_amount - COALESCE(qtyInOrdersNotShippedCTE.quantity, 0) as stock, s.image_source, s.service_fee, - IF(sp.price_rmb IS NULL, sp.price, + IF(sp.currency_id = (SELECT id FROM rmb_id), ( ROUND( - sp.price_rmb / - (SELECT rate - FROM exchange_rates - WHERE original_currency = 'EUR' AND target_currency = 'RMB' - ORDER BY create_time DESC LIMIT 1) + sp.price / + (SELECT rate FROM latest_exchange_rate) ,2) - ) + ), sp.price ) as sku_price, sp.threshold as discount_moq, - IF(sp.price_rmb IS NULL, sp.discounted_price, + IF(sp.currency_id = (SELECT id FROM rmb_id), ( ROUND( - sp.discounted_price_rmb / - (SELECT rate - FROM exchange_rates - WHERE target_currency = 'EUR' AND original_currency = 'RMB' - ORDER BY create_time DESC LIMIT 1) + sp.discounted_price / + (SELECT rate FROM latest_exchange_rate) ,2) - ) + ),sp.discounted_price ) as discounted_price, s7.quantity as sales_last_week, s28.quantity as sales_four_weeks, @@ -418,6 +421,9 @@ AND po.can_send = 1 AND poc.erp_status IN ('1','2') GROUP BY sku_id + ), + rmb_id AS ( + SELECT id FROM currency WHERE code = 'RMB' ) SELECT s.id, s.erp_code, @@ -429,28 +435,30 @@ s.available_amount + s.purchasing_amount - IF(qtyInOrdersNotShippedCTE.quantity IS NULL, 0, qtyInOrdersNotShippedCTE.quantity) as stock, s.image_source, s.service_fee, - IF(sp.price_rmb IS NULL, sp.price, + IF(sp.currency_id = (SELECT id FROM rmb_id), ( ROUND( - sp.price_rmb / + sp.price / (SELECT rate FROM exchange_rates WHERE original_currency = 'EUR' AND target_currency = 'RMB' ORDER BY create_time DESC LIMIT 1) - ,2) + ,2 ) + ), sp.price ) as sku_price, sp.threshold as discount_moq, - IF(sp.price_rmb IS NULL, sp.discounted_price, + IF(sp.currency_id = (SELECT id FROM rmb_id), ( ROUND( - sp.discounted_price_rmb / + sp.discounted_price / (SELECT rate FROM exchange_rates WHERE target_currency = 'EUR' AND original_currency = 'RMB' ORDER BY create_time DESC LIMIT 1) - ,2) + ,2 ) + ), sp.discounted_price ) as discounted_price, s7.quantity as sales_last_week, s28.quantity as sales_four_weeks, @@ -464,10 +472,7 @@ LEFT JOIN qtyInOrdersNotShippedCTE ON s.id = qtyInOrdersNotShippedCTE.ID WHERE client_sku.client_id = #{clientId} AND s.status = 3 - AND ( - (sp.price_rmb IS NOT NULL AND sp.price_rmb <> 0) - OR (sp.price IS NOT NULL AND sp.price <> 0) - ) + AND sp.price IS NOT NULL AND sp.price <> 0 ORDER BY s.erp_code ; diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/IClientService.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/IClientService.java index 25786bd08..b757c3026 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/IClientService.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/IClientService.java @@ -65,4 +65,6 @@ public interface IClientService extends IService { Client getByShopId(String shopId); Client getClientFromCredit(String invoiceNumber); + + List getClientsByCode(List clientCodes); } diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/IClientSkuService.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/IClientSkuService.java index d2e3e6f1b..efc82824c 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/IClientSkuService.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/IClientSkuService.java @@ -21,4 +21,6 @@ public interface IClientSkuService extends IService { void addClientSku(String clientId, String skuId); List getUnpairedSkus(); + + String getClientIdFromSkuId(String skuCode); } diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/IPurchaseOrderService.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/IPurchaseOrderService.java index 85ac01d63..c4e9b2e72 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/IPurchaseOrderService.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/IPurchaseOrderService.java @@ -72,7 +72,7 @@ public interface IPurchaseOrderService extends IService { String addPurchase(List SkuQuantity, List orderIDs) throws UserException; @Transactional - String addPurchase(String username, Client client, String invoiceNumber, List skuQuantities, Map> platformOrderIDs) throws UserException; + String addPurchase(String username, Client client, String invoiceNumber, List skuQuantities, Map> orderContentMap, List ordersWithStock) throws UserException; void savePaymentDocumentForPurchase(String purchaseID, MultipartFile in) throws IOException; diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/PlatformOrderShippingInvoiceService.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/PlatformOrderShippingInvoiceService.java index a61c2c8d8..b52b324f8 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/PlatformOrderShippingInvoiceService.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/PlatformOrderShippingInvoiceService.java @@ -98,8 +98,10 @@ public class PlatformOrderShippingInvoiceService { @Value("${jeecg.path.completeTemplatePath_US}") private String COMPLETE_INVOICE_TEMPLATE_US; - @Value("${jeecg.path.purchaseTemplatePath}") - private String PURCHASE_INVOICE_TEMPLATE; + @Value("${jeecg.path.purchaseTemplatePath_EU}") + private String PURCHASE_INVOICE_TEMPLATE_EU; + @Value("${jeecg.path.purchaseTemplatePath_US}") + private String PURCHASE_INVOICE_TEMPLATE_US; @Value("${jeecg.path.shippingInvoiceDir}") private String INVOICE_DIR; @@ -253,21 +255,11 @@ public class PlatformOrderShippingInvoiceService { return getInvoiceMetaDataAndInsert(username, invoice); } - /** - * Make a complete shipping invoice (purchase + shipping) invoice for specified orders and order statuses - * - * @param param the parameters to make the invoice - * @return name of the invoice, can be used to in {@code getInvoiceBinary}. - * @throws UserException exception due to error of user input, message will contain detail - * @throws ParseException exception because of format of "start" and "end" date does not follow - * pattern: "yyyy-MM-dd" - * @throws IOException exception related to invoice file IO. - */ @Transactional - public InvoiceMetaData makeCompleteInvoice(ShippingInvoiceOrderParam param) throws UserException, ParseException, IOException, MessagingException, InterruptedException { + public InvoiceMetaData makeManualCompleteInvoice(ManualInvoiceOrderParam param) throws UserException, ParseException, IOException, MessagingException, InterruptedException { String username = ((LoginUser) SecurityUtils.getSubject().getPrincipal()).getUsername(); // Creates invoice by factory - CompleteInvoice invoice = factory.createCompleteShippingInvoice(username, param.clientID(), null, param.orderIds(), param.getType(), param.getStart(), param.getEnd()); + CompleteInvoice invoice = factory.createCompleteShippingInvoice(username, param.getClientID(), null, param.getOrderIds(), param.getType(), null, null, param.getOrdersWithStock()); return getInvoiceMetaDataAndInsert(username, invoice); } @@ -292,7 +284,7 @@ public class PlatformOrderShippingInvoiceService { orderIds = platformOrderMapper.fetchUninvoicedOrderIDInShopsAndOrderTime(param.getStart(), param.getEnd(), param.shopIDs(), param.getErpStatuses(), param.getWarehouses()); } // Creates invoice by factory - CompleteInvoice invoice = factory.createCompleteShippingInvoice(username, param.clientID(), param.getBalance() ,orderIds, method, param.getStart(), param.getEnd()); + CompleteInvoice invoice = factory.createCompleteShippingInvoice(username, param.clientID(), param.getBalance() ,orderIds, method, param.getStart(), param.getEnd(), null); return getInvoiceMetaDataAndInsert(username, invoice); } @NotNull @@ -341,8 +333,11 @@ public class PlatformOrderShippingInvoiceService { @NotNull private InvoiceMetaData getInvoiceMetaData(PurchaseInvoice invoice) throws IOException { // Chooses invoice template based on client's preference on currency - Path template = Paths.get(PURCHASE_INVOICE_TEMPLATE ); - + Path template; + if(invoice.getTargetClient().getCurrency().equals("USD")) + template = Paths.get(PURCHASE_INVOICE_TEMPLATE_US ); + else + template = Paths.get(PURCHASE_INVOICE_TEMPLATE_EU); // Writes invoice content to a new excel file String filename = "Invoice N°" + invoice.getCode() + " (" + invoice.getTargetClient().getInvoiceEntity() + ").xlsx"; Path out = Paths.get(PURCHASE_INVOICE_DIR, filename); diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/impl/BalanceServiceImpl.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/impl/BalanceServiceImpl.java index 871fe5ee9..0250eda94 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/impl/BalanceServiceImpl.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/impl/BalanceServiceImpl.java @@ -64,6 +64,9 @@ public class BalanceServiceImpl extends ServiceImpl impl BigDecimal previousBalance = getBalanceByClientIdAndCurrency(clientId, currency); BigDecimal currentBalance = previousBalance.subtract(invoice.getFinalAmount()); BigDecimal purchaseFees = purchaseOrderService.getPurchaseFeesByInvoiceCode(invoiceCode); + if(purchaseFees == null) { + purchaseFees = BigDecimal.ZERO; + } currentBalance = currentBalance.subtract(purchaseFees); SysUser sysUser = new SysUser(); Balance balance = Balance.of(sysUser.getUsername(), clientId, invoice.getCurrencyId(), Balance.OperationType.Debit.name(), invoice.getId(), currentBalance); diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/impl/ClientServiceImpl.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/impl/ClientServiceImpl.java index 8f4f14fc6..b69bdb077 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/impl/ClientServiceImpl.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/impl/ClientServiceImpl.java @@ -180,4 +180,9 @@ public class ClientServiceImpl extends ServiceImpl impleme public Client getClientFromCredit(String invoiceNumber) { return clientMapper.getClientFromCredit(invoiceNumber); } + + @Override + public List getClientsByCode(List clientCodes) { + return clientMapper.getClientsByCode(clientCodes); + } } diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/impl/ClientSkuServiceImpl.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/impl/ClientSkuServiceImpl.java index 9a967b510..4d1b0ff37 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/impl/ClientSkuServiceImpl.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/impl/ClientSkuServiceImpl.java @@ -86,4 +86,9 @@ public class ClientSkuServiceImpl extends ServiceImpl getUnpairedSkus() { return clientSkuMapper.getUnpairedSkus(); } + + @Override + public String getClientIdFromSkuId(String skuId) { + return clientSkuMapper.getClientIdFromSkuId(skuId); + } } diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/impl/InvoiceServiceImpl.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/impl/InvoiceServiceImpl.java index 0717c0f9c..9bcfaa835 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/impl/InvoiceServiceImpl.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/impl/InvoiceServiceImpl.java @@ -129,7 +129,8 @@ public class InvoiceServiceImpl extends ServiceImpl impl else if(invoiceType.equalsIgnoreCase(COMPLETE.name())) { ShippingInvoice shippingInvoice = shippingInvoiceService.getById(id); PurchaseOrder purchase = purchaseOrderService.getPurchaseByInvoiceNumberAndClientId(invoiceNumber, clientId); - if(shippingInvoice == null || purchase == null) { + // we don't test if purchase is null, because certain clients can have complete invoices without purchase orders, eg: LA, AP + if(shippingInvoice == null) { log.error("Error while cancelling complete invoice : invoice or purchase not found for id : {}", id); return false; } @@ -143,23 +144,29 @@ public class InvoiceServiceImpl extends ServiceImpl impl log.error("Complete invoice {} older than {} days, client is not allowed to cancel it", invoiceNumber, CANCEL_DAYS_LIMIT); return false; } - if(!isEmployee && purchase.isOrdered()) { - log.error("Purchase order {} for invoice {} is already ordered, cannot be cancelled", id, invoiceNumber); - return false; + if(purchase != null) { + if (!isEmployee && purchase.isOrdered()) { + log.error("Purchase order {} for invoice {} is already ordered, cannot be cancelled", id, invoiceNumber); + return false; + } + if (purchase.getInventoryDocumentString() != null && !purchase.getInventoryDocumentString().isEmpty()) + shippingInvoiceService.deleteAttachmentFile(purchase.getInventoryDocumentString()); + if (purchase.getPaymentDocumentString() != null && !purchase.getPaymentDocumentString().isEmpty()) + shippingInvoiceService.deleteAttachmentFile(purchase.getPaymentDocumentString()); + purchaseOrderService.cancelInvoice(purchase.getId()); + } else { + log.info("Purchase order not found for invoice : {}", invoiceNumber); } - if(purchase.getInventoryDocumentString() != null && !purchase.getInventoryDocumentString().isEmpty()) - shippingInvoiceService.deleteAttachmentFile(purchase.getInventoryDocumentString()); - if(purchase.getPaymentDocumentString() != null && !purchase.getPaymentDocumentString().isEmpty()) - shippingInvoiceService.deleteAttachmentFile(purchase.getPaymentDocumentString()); platformOrderContentService.cancelInvoice(invoiceNumber, clientId); platformOrderMabangService.deleteOrderRemark(invoiceNumber); platformOrderService.removePurchaseInvoiceNumber(invoiceNumber, clientId); platformOrderService.cancelInvoice(invoiceNumber, clientId); - purchaseOrderService.cancelInvoice(purchase.getId()); shippingInvoiceService.cancelInvoice(id); // reminder : in complete invoicing balance is updated only once with shipping invoice ID and the amount is the sum of shipping fees and purchase fees - amount = shippingInvoice.getFinalAmount().add(purchase.getFinalAmount()); + amount = shippingInvoice.getFinalAmount(); + if(purchase != null) + amount = amount.add(purchase.getFinalAmount()); currencyId = shippingInvoice.getCurrencyId(); } else if(invoiceType.equalsIgnoreCase(CREDIT.name())) { diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/impl/purchase/PurchaseOrderServiceImpl.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/impl/purchase/PurchaseOrderServiceImpl.java index d7740fcbc..17c8f790a 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/impl/purchase/PurchaseOrderServiceImpl.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/impl/purchase/PurchaseOrderServiceImpl.java @@ -66,6 +66,8 @@ public class PurchaseOrderServiceImpl extends ServiceImpl skuQuantities, - Map> orderAndContent) throws UserException { + Map> orderAndContent, List ordersWithStock) throws UserException { Objects.requireNonNull(orderAndContent); List details = platformOrderService.searchPurchaseOrderDetail(skuQuantities); @@ -438,7 +442,15 @@ public class PurchaseOrderServiceImpl extends ServiceImpl orderIds = orderAndContent.keySet().stream() + .map(PlatformOrder::getId) + .collect(Collectors.toList()); + if( ordersWithStock != null && !ordersWithStock.isEmpty()) { + orderIds = orderIds.stream() + .filter(orderId -> !ordersWithStock.contains(orderId)) + .collect(Collectors.toList()); + } + skuService.addInventory(skuQuantities, orderIds); // 3. save the application of promotion information List promotionHistoryEntries = details.stream() @@ -459,6 +471,9 @@ public class PurchaseOrderServiceImpl extends ServiceImpl> entry : orderAndContent.entrySet()) { PlatformOrder platformOrder = entry.getKey(); + if(ordersWithStock != null && ordersWithStock.contains(platformOrder.getId())) + continue; + // TODO : what to do with order status ???????? List orderContents = entry.getValue(); platformOrder.setStatus(PlatformOrder.Status.Purchasing.code); for (PlatformOrderContent orderContent : orderContents) { @@ -533,22 +548,26 @@ public class PurchaseOrderServiceImpl extends ServiceImpl purchaseOrderSkuList = purchaseOrderContentMapper.selectInvoiceDataByID(purchaseID); List promotionDetails = skuPromotionHistoryMapper.selectPromotionByPurchase(purchaseID); String invoiceCode = purchaseOrderMapper.selectById(purchaseID).getInvoiceNumber(); BigDecimal eurToUsd = exchangeRatesMapper.getLatestExchangeRate("EUR", "USD"); String filename = "Invoice N°" + invoiceCode + " (" + client.getInvoiceEntity() + ").xlsx"; - Path template = Paths.get(INVOICE_TEMPLATE); + Path template; + if (client.getCurrency().equals("USD")) { + template = Paths.get(INVOICE_TEMPLATE_US); + } else { + template = Paths.get(INVOICE_TEMPLATE_EU); + } Path newInvoice = Paths.get(INVOICE_DIR, filename); Files.copy(template, newInvoice, StandardCopyOption.REPLACE_EXISTING); PurchaseInvoice pv = new PurchaseInvoice(client, invoiceCode, "Purchase Invoice", purchaseOrderSkuList, promotionDetails, eurToUsd); @@ -558,6 +577,7 @@ public class PurchaseOrderServiceImpl extends ServiceImpl purchaseOrderSkuList = new ArrayList<>(); // -5 because we have at least 5 lines of promotions for (int i = 0; i < nbOfLines - 5; i++) { @@ -571,7 +591,11 @@ public class PurchaseOrderServiceImpl extends ServiceImpl orderIds; + private final String type; + private final List ordersWithStock = new ArrayList<>(); + public ManualInvoiceOrderParam(@JsonProperty("clientID") String clientID, @JsonProperty("orderIds") List orderIds, @JsonProperty("type") String type, @JsonProperty("ordersWithStock") List ordersWithStock) { + this.clientID = clientID; + this.orderIds = orderIds; + this.type = type; + if (ordersWithStock != null) { + this.ordersWithStock.addAll(ordersWithStock); + } + } +} diff --git a/jeecg-module-system/jeecg-system-start/src/main/resources/application-prod.yml b/jeecg-module-system/jeecg-system-start/src/main/resources/application-prod.yml index 28cc14eae..3dbd02089 100644 --- a/jeecg-module-system/jeecg-system-start/src/main/resources/application-prod.yml +++ b/jeecg-module-system/jeecg-system-start/src/main/resources/application-prod.yml @@ -229,7 +229,8 @@ jeecg: creditInvoiceDir: /wia/invoices/credit # purchase invoice template - purchaseTemplatePath: /wia/files/Purchase_Invoice_Template.xlsx + purchaseTemplatePath_EU: /wia/files/Purchase_Invoice_Template_EU.xlsx + purchaseTemplatePath_US: /wia/files/Purchase_Invoice_Template_US.xlsx # where to store generated file purchaseInvoiceDir: /wia/invoices/purchase purchaseInvoiceTestDir: /wia/invoices/test/purchase