mirror of https://github.com/jeecgboot/jeecg-boot
feat: client sku purchase access, purchase invoice USD fix, complete invoice bypass stock
parent
4926576b70
commit
b07318a891
|
@ -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")) {
|
||||
|
|
|
@ -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<String, Object> 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<String, Integer> 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<SkuQuantity> skuQuantities = new ArrayList<>();
|
||||
for(Map.Entry<String, Integer> 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 {
|
||||
|
|
|
@ -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<String> 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
|
||||
* <p>
|
||||
* To generate an invoice, it
|
||||
* <ol>
|
||||
|
@ -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<String> orderIds, String shippingMethod, String start, String end) throws UserException, MessagingException, InterruptedException {
|
||||
public CompleteInvoice createCompleteShippingInvoice(String username, String customerId, BigDecimal balance, List<String> orderIds, String shippingMethod, String start, String end, List<String> 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<PlatformOrder, List<PlatformOrderContent>> uninvoicedOrderToContent = platformOrderService.fetchUninvoicedOrderDataForUpdate(orderIds);
|
||||
|
@ -184,19 +189,32 @@ public class ShippingInvoiceFactory {
|
|||
.collect(Collectors.toList());
|
||||
List<ExtraFeeResult> 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<String> shopIds,
|
||||
Map<PlatformOrder, List<PlatformOrderContent>> orderAndContent,
|
||||
List<SavRefundWithDetail> savRefunds, List<ExtraFeeResult> extraFees, String subject) throws UserException {
|
||||
List<SavRefundWithDetail> savRefunds, List<ExtraFeeResult> extraFees, String subject, List<String> ordersWithStock) throws UserException {
|
||||
Client client = clientMapper.selectById(customerId);
|
||||
log.info("User {} is creating a complete invoice for customer {}", username, client.getInternalCode());
|
||||
|
||||
|
@ -251,14 +269,22 @@ 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<String> orderIds = orderAndContent.keySet().stream().map(PlatformOrder::getId).collect(toList());
|
||||
List<PurchaseInvoiceEntry> purchaseOrderSkuList = new ArrayList<>();
|
||||
List<PromotionDetail> promotionDetails = new ArrayList<>();
|
||||
List<String> 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(!orderIds.isEmpty()){
|
||||
List<SkuQuantity> skuQuantities = platformOrderContentService.searchOrderContent(orderIds);
|
||||
|
||||
String purchaseID = purchaseOrderService.addPurchase(username, client, invoiceCode, skuQuantities, orderAndContent);
|
||||
String purchaseID = purchaseOrderService.addPurchase(username, client, invoiceCode, skuQuantities, orderAndContent, ordersWithStock);
|
||||
|
||||
List<PurchaseInvoiceEntry> purchaseOrderSkuList = purchaseOrderContentMapper.selectInvoiceDataByID(purchaseID);
|
||||
List<PromotionDetail> promotionDetails = skuPromotionHistoryMapper.selectPromotionByPurchase(purchaseID);
|
||||
purchaseOrderSkuList = purchaseOrderContentMapper.selectInvoiceDataByID(purchaseID);
|
||||
promotionDetails = skuPromotionHistoryMapper.selectPromotionByPurchase(purchaseID);
|
||||
if (savRefunds != null) {
|
||||
updateSavRefundsInDb(savRefunds, invoiceCode);
|
||||
}
|
||||
|
@ -266,6 +292,7 @@ public class ShippingInvoiceFactory {
|
|||
List<String> extraFeesIds = extraFees.stream().map(ExtraFeeResult::getId).collect(toList());
|
||||
extraFeeService.updateInvoiceNumberByIds(extraFeesIds, invoiceCode);
|
||||
}
|
||||
}
|
||||
updateOrdersAndContentsInDb(orderAndContent);
|
||||
|
||||
return new CompleteInvoice(client, invoiceCode, subject, orderAndContent, savRefunds, extraFees,
|
||||
|
@ -391,7 +418,7 @@ public class ShippingInvoiceFactory {
|
|||
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);
|
||||
String purchaseID = purchaseOrderService.addPurchase(username, client, invoiceCode, skuQuantities, orderAndContent, null);
|
||||
|
||||
List<PurchaseInvoiceEntry> purchaseOrderSkuList = purchaseOrderContentMapper.selectInvoiceDataByID(purchaseID);
|
||||
List<PromotionDetail> promotionDetails = skuPromotionHistoryMapper.selectPromotionByPurchase(purchaseID);
|
||||
|
|
|
@ -38,4 +38,6 @@ public interface ClientMapper extends BaseMapper<Client> {
|
|||
Client getByShopId(@Param("shopId") String shopId);
|
||||
|
||||
Client getClientFromCredit(@Param("invoiceNumber") String invoiceNumber);
|
||||
|
||||
List<String> getClientsByCode(@Param("codes") List<String> clientCodes);
|
||||
}
|
||||
|
|
|
@ -21,4 +21,6 @@ public interface ClientSkuMapper extends BaseMapper<ClientSku> {
|
|||
List<ClientSku> selectByMainId(@Param("mainId") String mainId);
|
||||
|
||||
List<Sku> getUnpairedSkus();
|
||||
|
||||
String getClientIdFromSkuId(@Param("skuId") String skuId);
|
||||
}
|
||||
|
|
|
@ -107,4 +107,13 @@
|
|||
JOIN credit ON c.id = credit.client_id
|
||||
WHERE credit.invoice_number = #{invoiceNumber};
|
||||
</select>
|
||||
<select id="getClientsByCode" resultType="java.lang.String">
|
||||
SELECT c.id
|
||||
FROM client c
|
||||
WHERE c.internal_code IN
|
||||
<foreach collection="codes" item="code" index="index" separator="," open="(" close=")">
|
||||
#{code}
|
||||
</foreach>
|
||||
AND c.active = 1;
|
||||
</select>
|
||||
</mapper>
|
|
@ -6,7 +6,8 @@
|
|||
DELETE
|
||||
FROM client_sku
|
||||
WHERE
|
||||
client_id = #{mainId} </delete>
|
||||
client_id = #{mainId}
|
||||
</delete>
|
||||
|
||||
<select id="selectByMainId" parameterType="java.lang.String" resultType="org.jeecg.modules.business.entity.ClientSku">
|
||||
SELECT *
|
||||
|
@ -20,4 +21,9 @@
|
|||
LEFT JOIN client_sku cs ON s.id = cs.sku_id
|
||||
WHERE cs.sku_id IS NULL;
|
||||
</select>
|
||||
<select id="getClientIdFromSkuId" resultType="java.lang.String">
|
||||
SELECT client_id
|
||||
FROM client_sku
|
||||
WHERE sku_id = #{skuId}
|
||||
</select>
|
||||
</mapper>
|
||||
|
|
|
@ -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
|
||||
;
|
||||
</select>
|
||||
|
|
|
@ -65,4 +65,6 @@ public interface IClientService extends IService<Client> {
|
|||
Client getByShopId(String shopId);
|
||||
|
||||
Client getClientFromCredit(String invoiceNumber);
|
||||
|
||||
List<String> getClientsByCode(List<String> clientCodes);
|
||||
}
|
||||
|
|
|
@ -21,4 +21,6 @@ public interface IClientSkuService extends IService<ClientSku> {
|
|||
void addClientSku(String clientId, String skuId);
|
||||
|
||||
List<Sku> getUnpairedSkus();
|
||||
|
||||
String getClientIdFromSkuId(String skuCode);
|
||||
}
|
||||
|
|
|
@ -72,7 +72,7 @@ public interface IPurchaseOrderService extends IService<PurchaseOrder> {
|
|||
String addPurchase(List<SkuQuantity> SkuQuantity, List<String> orderIDs) throws UserException;
|
||||
|
||||
@Transactional
|
||||
String addPurchase(String username, Client client, String invoiceNumber, List<SkuQuantity> skuQuantities, Map<PlatformOrder, List<PlatformOrderContent>> platformOrderIDs) throws UserException;
|
||||
String addPurchase(String username, Client client, String invoiceNumber, List<SkuQuantity> skuQuantities, Map<PlatformOrder, List<PlatformOrderContent>> orderContentMap, List<String> ordersWithStock) throws UserException;
|
||||
|
||||
void savePaymentDocumentForPurchase(String purchaseID, MultipartFile in) throws IOException;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -64,6 +64,9 @@ public class BalanceServiceImpl extends ServiceImpl<BalanceMapper, Balance> 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);
|
||||
|
|
|
@ -180,4 +180,9 @@ public class ClientServiceImpl extends ServiceImpl<ClientMapper, Client> impleme
|
|||
public Client getClientFromCredit(String invoiceNumber) {
|
||||
return clientMapper.getClientFromCredit(invoiceNumber);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getClientsByCode(List<String> clientCodes) {
|
||||
return clientMapper.getClientsByCode(clientCodes);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -86,4 +86,9 @@ public class ClientSkuServiceImpl extends ServiceImpl<ClientSkuMapper, ClientSku
|
|||
public List<Sku> getUnpairedSkus() {
|
||||
return clientSkuMapper.getUnpairedSkus();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getClientIdFromSkuId(String skuId) {
|
||||
return clientSkuMapper.getClientIdFromSkuId(skuId);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -129,7 +129,8 @@ public class InvoiceServiceImpl extends ServiceImpl<InvoiceMapper, Invoice> 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,6 +144,7 @@ public class InvoiceServiceImpl extends ServiceImpl<InvoiceMapper, Invoice> impl
|
|||
log.error("Complete invoice {} older than {} days, client is not allowed to cancel it", invoiceNumber, CANCEL_DAYS_LIMIT);
|
||||
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;
|
||||
|
@ -151,15 +153,20 @@ public class InvoiceServiceImpl extends ServiceImpl<InvoiceMapper, Invoice> impl
|
|||
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);
|
||||
}
|
||||
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())) {
|
||||
|
|
|
@ -66,6 +66,8 @@ public class PurchaseOrderServiceImpl extends ServiceImpl<PurchaseOrderMapper, P
|
|||
private ICurrencyService currencyService;
|
||||
@Autowired
|
||||
private IInvoiceNumberReservationService invoiceNumberReservationService;
|
||||
@Autowired
|
||||
private ISecurityService securityService;
|
||||
|
||||
/**
|
||||
* Directory where payment documents are put
|
||||
|
@ -73,8 +75,10 @@ public class PurchaseOrderServiceImpl extends ServiceImpl<PurchaseOrderMapper, P
|
|||
@Value("${jeecg.path.save}")
|
||||
private String PAYMENT_DOC_DIR;
|
||||
|
||||
@Value("${jeecg.path.purchaseTemplatePath}")
|
||||
private String INVOICE_TEMPLATE;
|
||||
@Value("${jeecg.path.purchaseTemplatePath_EU}")
|
||||
private String INVOICE_TEMPLATE_EU;
|
||||
@Value("${jeecg.path.purchaseTemplatePath_US}")
|
||||
private String INVOICE_TEMPLATE_US;
|
||||
|
||||
@Value("${jeecg.path.purchaseInvoiceDir}")
|
||||
private String INVOICE_DIR;
|
||||
|
@ -403,7 +407,7 @@ public class PurchaseOrderServiceImpl extends ServiceImpl<PurchaseOrderMapper, P
|
|||
@Override
|
||||
@Transactional
|
||||
public String addPurchase(String username, Client client, String invoiceNumber, List<SkuQuantity> skuQuantities,
|
||||
Map<PlatformOrder, List<PlatformOrderContent>> orderAndContent) throws UserException {
|
||||
Map<PlatformOrder, List<PlatformOrderContent>> orderAndContent, List<String> ordersWithStock) throws UserException {
|
||||
Objects.requireNonNull(orderAndContent);
|
||||
|
||||
List<OrderContentDetail> details = platformOrderService.searchPurchaseOrderDetail(skuQuantities);
|
||||
|
@ -438,7 +442,15 @@ public class PurchaseOrderServiceImpl extends ServiceImpl<PurchaseOrderMapper, P
|
|||
purchaseOrderContentMapper.addAll(username, purchaseID, entries);
|
||||
|
||||
// 2.1 save extra sku
|
||||
skuService.addInventory(skuQuantities, orderAndContent.keySet().stream().map(PlatformOrder::getId).collect(Collectors.toList()));
|
||||
List<String> 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<PromotionHistoryEntry> promotionHistoryEntries = details.stream()
|
||||
|
@ -459,6 +471,9 @@ public class PurchaseOrderServiceImpl extends ServiceImpl<PurchaseOrderMapper, P
|
|||
}
|
||||
for (Map.Entry<PlatformOrder, List<PlatformOrderContent>> entry : orderAndContent.entrySet()) {
|
||||
PlatformOrder platformOrder = entry.getKey();
|
||||
if(ordersWithStock != null && ordersWithStock.contains(platformOrder.getId()))
|
||||
continue;
|
||||
// TODO : what to do with order status ????????
|
||||
List<PlatformOrderContent> orderContents = entry.getValue();
|
||||
platformOrder.setStatus(PlatformOrder.Status.Purchasing.code);
|
||||
for (PlatformOrderContent orderContent : orderContents) {
|
||||
|
@ -533,22 +548,26 @@ public class PurchaseOrderServiceImpl extends ServiceImpl<PurchaseOrderMapper, P
|
|||
|
||||
@Override
|
||||
public InvoiceMetaData makeInvoice(String purchaseID) throws IOException, UserException {
|
||||
Client client = clientService.getCurrentClient();
|
||||
if(client == null) {
|
||||
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
|
||||
if (sysUser.getOrgCode().contains("A01") || sysUser.getOrgCode().contains("A03")) {
|
||||
client = clientService.getClientFromPurchase(purchaseID);
|
||||
}
|
||||
else
|
||||
boolean isEmployee = securityService.checkIsEmployee();
|
||||
Client client;
|
||||
if(!isEmployee) {
|
||||
client = clientService.getCurrentClient();
|
||||
if (client == null)
|
||||
throw new UserException("User is not a client");
|
||||
}
|
||||
} else
|
||||
client = clientService.getClientFromPurchase(purchaseID);
|
||||
List<PurchaseInvoiceEntry> purchaseOrderSkuList = purchaseOrderContentMapper.selectInvoiceDataByID(purchaseID);
|
||||
List<PromotionDetail> 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<PurchaseOrderMapper, P
|
|||
@Override
|
||||
public InvoiceMetaData makeInvoiceTest(int nbOfLines) throws Exception {
|
||||
Client client = clientService.getClientBySku("test");
|
||||
client.setCurrency("USD");
|
||||
List<PurchaseInvoiceEntry> 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<PurchaseOrderMapper, P
|
|||
BigDecimal eurToUsd = exchangeRatesMapper.getLatestExchangeRate("EUR", "USD");
|
||||
|
||||
String filename = "Invoice N°" + invoiceCode + " (" + client.getInvoiceEntity() + ")_" + nbOfLines + ".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_TEST_DIR, filename);
|
||||
Files.copy(template, newInvoice, StandardCopyOption.REPLACE_EXISTING);
|
||||
PurchaseInvoice pv = new PurchaseInvoice(client, invoiceCode, "Purchase Invoice", purchaseOrderSkuList, promotionDetails, eurToUsd);
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
package org.jeecg.modules.business.vo;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class ManualInvoiceOrderParam {
|
||||
private final String clientID;
|
||||
private final List<String> orderIds;
|
||||
private final String type;
|
||||
private final List<String> ordersWithStock = new ArrayList<>();
|
||||
public ManualInvoiceOrderParam(@JsonProperty("clientID") String clientID, @JsonProperty("orderIds") List<String> orderIds, @JsonProperty("type") String type, @JsonProperty("ordersWithStock") List<String> ordersWithStock) {
|
||||
this.clientID = clientID;
|
||||
this.orderIds = orderIds;
|
||||
this.type = type;
|
||||
if (ordersWithStock != null) {
|
||||
this.ordersWithStock.addAll(ordersWithStock);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue