Merge pull request #127 from LQYBill/feat/clientInvoicingOptimization

Feat/client invoicing optimization
pull/8040/head
Qiuyi LI 2024-12-23 17:14:27 +01:00 committed by GitHub
commit 47a9149549
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 237 additions and 15 deletions

View File

@ -222,24 +222,23 @@ public class PurchaseOrderController {
platformOrderService.removePurchaseInvoiceNumber(purchaseOrder.getInvoiceNumber(), purchaseOrder.getClientId()); platformOrderService.removePurchaseInvoiceNumber(purchaseOrder.getInvoiceNumber(), purchaseOrder.getClientId());
List<PlatformOrder> platformOrders = platformOrderService.selectByPlatformOrderIds(platformOrderIds); List<PlatformOrder> platformOrders = platformOrderService.selectByPlatformOrderIds(platformOrderIds);
log.info("Platform orders found for attribution : {}", platformOrders.stream().map(PlatformOrder::getPlatformOrderId).collect(Collectors.toList())); log.info("Platform orders found for attribution : {}", platformOrders.stream().map(PlatformOrder::getPlatformOrderId).collect(Collectors.toList()));
Map<String, List<String>> platformOrderIdUpdateMap = new HashMap<>(); Map<String, Responses> responsesMappedByReason = new HashMap<>();
Responses platformOrderIdUpdateResponse = new Responses();
if(!platformOrders.isEmpty()) { if(!platformOrders.isEmpty()) {
for(PlatformOrder po : platformOrders) { for(PlatformOrder po : platformOrders) {
po.setPurchaseInvoiceNumber(purchaseOrder.getInvoiceNumber()); po.setPurchaseInvoiceNumber(purchaseOrder.getInvoiceNumber());
platformOrderIds.remove(po.getPlatformOrderId()); platformOrderIds.remove(po.getPlatformOrderId());
if(platformOrderIdUpdateMap.get("success") != null) platformOrderIdUpdateResponse.addSuccess(po.getPlatformOrderId());
platformOrderIdUpdateMap.get("success").add(po.getPlatformOrderId());
else
platformOrderIdUpdateMap.put("success", new ArrayList<>(Collections.singletonList(po.getPlatformOrderId())));
} }
platformOrderService.updateBatchById(platformOrders); platformOrderService.updateBatchById(platformOrders);
} }
if(!platformOrderIds.isEmpty()) { if(!platformOrderIds.isEmpty()) {
log.error("Platform orders not found: {}", platformOrderIds); log.error("Platform orders not found: {}", platformOrderIds);
platformOrderIdUpdateMap.put("fail", platformOrderIds); platformOrderIdUpdateResponse.getFailures().addAll(platformOrderIds);
} }
purchaseOrderService.updateById(purchaseOrder); purchaseOrderService.updateById(purchaseOrder);
return Result.OK("sys.api.entryEditSuccess", platformOrderIdUpdateMap); responsesMappedByReason.put("Platform Order IDs Update / 平台订单号码更新 : " + purchaseOrder.getInvoiceNumber(), platformOrderIdUpdateResponse);
return Result.OK("sys.api.entryEditSuccess", responsesMappedByReason);
} }
/** /**

View File

@ -11,7 +11,6 @@ import freemarker.template.TemplateException;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils; import org.apache.shiro.SecurityUtils;
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.common.system.api.ISysBaseAPI;
import org.jeecg.common.system.query.QueryGenerator; import org.jeecg.common.system.query.QueryGenerator;
@ -626,18 +625,53 @@ public class InvoiceController {
@RequestParam("type") String type @RequestParam("type") String type
) throws IOException, UserException { ) throws IOException, UserException {
log.info("Request for downloading invoice detail by client and period : \nclient : {} \nshops : {}\nstart date : {}\nend date : {}\ntype : {}", clientId, shopIds, startDate, endDate, type); log.info("Request for downloading invoice detail by client and period : \nclient : {} \nshops : {}\nstart date : {}\nend date : {}\ntype : {}", clientId, shopIds, startDate, endDate, type);
List<FactureDetail> invoiceDetails = shippingInvoiceService.getInvoiceDetailByShopsAndPeriod(shopIds, startDate, endDate, type); boolean isEmployee = securityService.checkIsEmployee();
Client client = clientService.getById(clientId); Client client = clientService.getById(clientId);
Client currentClient;
if(client == null) {
log.error("Client {} not found", clientId);
return new byte[0];
}
if (!isEmployee) {
currentClient = clientService.getCurrentClient();
if (currentClient == null) {
log.error("Client is not registered as a user : {}", clientId);
return new byte[0];
}
if(!clientId.equals(currentClient.getId())) {
log.error("Client {} is not authorized to download invoice detail for client {}", currentClient.getInternalCode(), client.getInternalCode());
return new byte[0];
}
}
List<FactureDetail> invoiceDetails = shippingInvoiceService.getInvoiceDetailByShopsAndPeriod(shopIds, startDate, endDate, type);
String period = startDate + "-" + endDate; String period = startDate + "-" + endDate;
return shippingInvoiceService.exportToExcel(invoiceDetails, Collections.emptyList(), Collections.emptyList(), period, client.getInvoiceEntity(), client.getInternalCode()); return shippingInvoiceService.exportToExcel(invoiceDetails, Collections.emptyList(), Collections.emptyList(), period, client.getInvoiceEntity(), client.getInternalCode());
} }
/**
* Only downloads the inventory of skus that are in the invoice
* Whereas downloadInventory downloads the inventory of a list of skus for the client
* @param invoiceCode
* @param internalCode
* @param invoiceEntity
* @return
* @throws IOException
*/
@GetMapping(value = "/downloadInvoiceInventory") @GetMapping(value = "/downloadInvoiceInventory")
public byte[] downloadInvoiceInventory(@RequestParam("invoiceCode") String invoiceCode, @RequestParam("internalCode") String internalCode, @RequestParam("invoiceEntity") String invoiceEntity) throws IOException { public byte[] downloadInvoiceInventory(@RequestParam("invoiceCode") String invoiceCode, @RequestParam("internalCode") String internalCode, @RequestParam("invoiceEntity") String invoiceEntity) throws IOException {
InvoiceMetaData metaData = new InvoiceMetaData("", invoiceCode, internalCode, invoiceEntity, ""); InvoiceMetaData metaData = new InvoiceMetaData("", invoiceCode, internalCode, invoiceEntity, "");
List<SkuOrderPage> skuOrderPages = skuService.getInventoryByInvoiceNumber(metaData.getInvoiceCode()); List<SkuOrderPage> skuOrderPages = skuService.getInventoryByInvoiceNumber(metaData.getInvoiceCode());
return shippingInvoiceService.exportPurchaseInventoryToExcel(skuOrderPages, metaData); return shippingInvoiceService.exportPurchaseInventoryToExcel(skuOrderPages, metaData);
} }
/**
* Downloads the inventory of skus for the client
* @param invoiceCode
* @param internalCode
* @param invoiceEntity
* @return
* @throws IOException
*/
@GetMapping(value = "/downloadInventory") @GetMapping(value = "/downloadInventory")
public byte[] downloadInventory(@RequestParam("invoiceCode") String invoiceCode, @RequestParam("internalCode") String internalCode, @RequestParam("invoiceEntity") String invoiceEntity) throws IOException { public byte[] downloadInventory(@RequestParam("invoiceCode") String invoiceCode, @RequestParam("internalCode") String internalCode, @RequestParam("invoiceEntity") String invoiceEntity) throws IOException {
InvoiceMetaData metaData = new InvoiceMetaData("", invoiceCode, internalCode, invoiceEntity, ""); InvoiceMetaData metaData = new InvoiceMetaData("", invoiceCode, internalCode, invoiceEntity, "");

View File

@ -0,0 +1,123 @@
package org.jeecg.modules.business.domain.api.mabang.doSearchSkuListNew;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.modules.business.domain.api.mabang.getorderlist.NetworkDataStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.NoSuchElementException;
/**
* This class provide stream of order.
*/
@Slf4j
public class UnpairedSkuListStream implements NetworkDataStream<SkuData> {
private final NetworkDataStream<SkuListResponse> rawStream;
private List<SkuData> skus;
private int index;
private boolean began;
/**
* Flag of current data is already empty,
* either currentOrders is null or currentIndex arrives at the end.
* In both case, we should call next() of the rawStream.
*/
private boolean empty;
public UnpairedSkuListStream(NetworkDataStream<SkuListResponse> rawStream) {
this.rawStream = rawStream;
skus = null;
this.index = 0;
this.empty = true;
this.began = false;
}
@Override
public List<SkuData> all() {
SkuData firstElement = attempt();
if (firstElement == null) {
return Collections.emptyList();
}
ArrayList<SkuData> res = new ArrayList<>();
if (firstElement.getStatus().equals(SkuStatus.AutomaticallyCreated)) {
res.add(firstElement);
}
while (hasNext()) {
SkuData nextSku = next();
if(nextSku.getStatus().equals(SkuStatus.AutomaticallyCreated)) {
res.add(nextSku);
}
}
return res;
}
@Override
public SkuData attempt() {
began = true;
log.info("Attempting for the first request");
SkuListResponse response = rawStream.attempt();
if (response == null) {
log.info("No response");
return null;
}
if (response.getData().isEmpty()) {
log.info("Response with empty data");
return null;
}
skus = response.getData().toJavaList(SkuData.class);
log.info("Raw response: {}", response.getData());
index = 1;
log.info("Returned the first element");
empty = index >= skus.size();
return skus.get(0);
}
@Override
public boolean hasNext() {
// the first time
if (!began) {
throw new IllegalStateException("Calling hasNext before begin");
}
// Current data is not yet empty
if (index < skus.size()) {
log.debug("Current order list is not empty yet");
return true;
}
/* Current data is empty */
this.empty = true;
log.debug("Current order list is already empty,");
// and raw stream is empty too.
if (!rawStream.hasNext()) {
log.debug("and source stream is empty too, hasNext: false");
return false;
}
// but raw stream not empty.
else {
log.debug("but source stream still has data, hasNext: true");
return true;
}
}
@Override
public SkuData next() {
if (!hasNext()) {
throw new NoSuchElementException("Stream is empty!");
}
if (empty) {
skus = this.rawStream.next().getData().toJavaList(SkuData.class);
empty = false;
index = 0;
}
log.debug("Return data at {}", index);
SkuData res = skus.get(index);
index++;
return res;
}
}

View File

@ -8,19 +8,23 @@ import java.util.function.Function;
public class AddPurchaseOrderRequestBody implements RequestBody { public class AddPurchaseOrderRequestBody implements RequestBody {
private String providerName; private String providerName;
private String employeeName; private final String employeeName;
private String content; private final String content;
private List<SkuStockData> stockData; private final List<SkuStockData> stockData;
private final static String DEFAULT_WAREHOUSE_NAME = "SZBA宝安仓"; private final static String DEFAULT_WAREHOUSE_NAME = "SZBA宝安仓";
private final static String TEMPORARY_PROVIDER_NAME = "临时供货商";
public AddPurchaseOrderRequestBody(String employeeName, String providerName, String content, List<SkuStockData> stockData) { public AddPurchaseOrderRequestBody(String employeeName, String providerName, String content, List<SkuStockData> stockData) {
this.stockData = stockData; this.stockData = stockData;
this.providerName = providerName; setProviderName(providerName);
this.employeeName = employeeName; this.employeeName = employeeName;
this.content = content; this.content = content;
} }
public void setProviderName(String providerName) {
this.providerName = providerName == null || providerName.isEmpty() ? TEMPORARY_PROVIDER_NAME : providerName;
}
@Override @Override
public String api() { public String api() {
return "pur-do-add-purchase"; return "pur-do-add-purchase";

View File

@ -0,0 +1,50 @@
package org.jeecg.modules.business.domain.job;
import lombok.extern.slf4j.Slf4j;
import org.codehaus.jettison.json.JSONException;
import org.codehaus.jettison.json.JSONObject;
import org.jeecg.modules.business.domain.api.mabang.doSearchSkuListNew.*;
import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
@Slf4j
@Component
public class MabangUnpairedSkuJob implements Job {
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
JobDataMap jobDataMap = context.getMergedJobDataMap();
List<String> skuList = new ArrayList<>();
String parameter = ((String) jobDataMap.get("parameter"));
if (parameter != null) {
try {
JSONObject jsonObject = new JSONObject(parameter);
if (!jsonObject.isNull("skus")) {
for (int i = 0; i < jsonObject.getJSONArray("skus").length(); i++) {
skuList.add(jsonObject.getJSONArray("skus").getString(i));
}
}
} catch (JSONException e) {
log.error("Error while parsing parameter as JSON, falling back to default parameters.");
}
}
if(skuList.isEmpty()) {
log.error("No skus provided, exiting job.");
return;
}
SkuListRequestBody body = new SkuListRequestBody();
body.setStockSkuList(String.join(",", skuList));
SkuListRawStream rawStream = new SkuListRawStream(body);
UnpairedSkuListStream stream = new UnpairedSkuListStream(rawStream);
List<SkuData> skusFromMabang = stream.all();
// System.out.println("skus from mabang : " + skusFromMabang);
}
}

View File

@ -715,6 +715,7 @@
) AS shipping_available, ) AS shipping_available,
MIN( MIN(
CASE CASE
WHEN poc.id IS NULL OR sku.id IS NULL THEN -1
WHEN po.purchase_invoice_number IS NULL AND stats.price_count = 0 THEN -1 WHEN po.purchase_invoice_number IS NULL AND stats.price_count = 0 THEN -1
WHEN po.purchase_invoice_number IS NOT NULL AND pur.paid_amount > 0.00 THEN 2 WHEN po.purchase_invoice_number IS NOT NULL AND pur.paid_amount > 0.00 THEN 2
WHEN po.purchase_invoice_number IS NOT NULL AND pur.paid_amount = 0.00 THEN 1 WHEN po.purchase_invoice_number IS NOT NULL AND pur.paid_amount = 0.00 THEN 1

View File

@ -107,7 +107,7 @@
JOIN client c ON s.owner_id = c.id JOIN client c ON s.owner_id = c.id
JOIN client_category cc ON c.client_category_id = cc.id JOIN client_category cc ON c.client_category_id = cc.id
WHERE po.erp_status IN (1,2) WHERE po.erp_status IN (1,2)
AND cc.name = 'self-service' AND cc.name IN ('self-service', 'confirmed')
AND po.order_time &gt;= #{start} AND po.order_time &gt;= #{start}
ORDER BY po.order_time ORDER BY po.order_time
), ),

View File

@ -85,6 +85,8 @@ public class PlatformOrderShippingInvoiceService {
@Autowired @Autowired
private IShopService shopService; private IShopService shopService;
@Autowired @Autowired
private ISkuService skuService;
@Autowired
CountryService countryService; CountryService countryService;
@Autowired @Autowired
IPurchaseOrderService purchaseOrderService; IPurchaseOrderService purchaseOrderService;
@ -791,6 +793,10 @@ public class PlatformOrderShippingInvoiceService {
log.info("File asked is of type invoice detail"); log.info("File asked is of type invoice detail");
pathList = getPath(INVOICE_DETAIL_DIR, invoiceNumber); pathList = getPath(INVOICE_DETAIL_DIR, invoiceNumber);
} }
if(filetype.equals("inventory")) {
log.info("File asked is of type inventory");
pathList = getPath(PURCHASE_INVENTORY_DIR, invoiceNumber);
}
if(pathList.isEmpty()) { if(pathList.isEmpty()) {
log.error("NO INVOICE FILE FOUND : " + invoiceNumber); log.error("NO INVOICE FILE FOUND : " + invoiceNumber);
log.info("Generating a new invoice file ..."); log.info("Generating a new invoice file ...");
@ -803,6 +809,11 @@ public class PlatformOrderShippingInvoiceService {
List<ExtraFeeResult> extraFees = extraFeeService.findByInvoiceNumber(invoiceNumber); List<ExtraFeeResult> extraFees = extraFeeService.findByInvoiceNumber(invoiceNumber);
exportToExcel(details, refunds, extraFees, invoiceNumber, client.getInvoiceEntity(), client.getInternalCode()); exportToExcel(details, refunds, extraFees, invoiceNumber, client.getInvoiceEntity(), client.getInternalCode());
pathList = getPath(INVOICE_DETAIL_DIR, invoiceNumber); pathList = getPath(INVOICE_DETAIL_DIR, invoiceNumber);
} else if (filetype.equals("inventory")) {
InvoiceMetaData metaData = purchaseOrderService.getMetaDataFromInvoiceNumbers(invoiceNumber);
List<SkuOrderPage> skuOrderPages = skuService.getInventoryByInvoiceNumber(metaData.getInvoiceCode());
exportPurchaseInventoryToExcel(skuOrderPages, metaData);
pathList = getPath(PURCHASE_INVENTORY_DIR, invoiceNumber);
} }
else { else {
return "ERROR"; return "ERROR";