mirror of https://github.com/jeecgboot/jeecg-boot
Merge pull request #127 from LQYBill/feat/clientInvoicingOptimization
Feat/client invoicing optimizationpull/8040/head
commit
47a9149549
|
@ -222,24 +222,23 @@ public class PurchaseOrderController {
|
|||
platformOrderService.removePurchaseInvoiceNumber(purchaseOrder.getInvoiceNumber(), purchaseOrder.getClientId());
|
||||
List<PlatformOrder> platformOrders = platformOrderService.selectByPlatformOrderIds(platformOrderIds);
|
||||
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()) {
|
||||
for(PlatformOrder po : platformOrders) {
|
||||
po.setPurchaseInvoiceNumber(purchaseOrder.getInvoiceNumber());
|
||||
platformOrderIds.remove(po.getPlatformOrderId());
|
||||
if(platformOrderIdUpdateMap.get("success") != null)
|
||||
platformOrderIdUpdateMap.get("success").add(po.getPlatformOrderId());
|
||||
else
|
||||
platformOrderIdUpdateMap.put("success", new ArrayList<>(Collections.singletonList(po.getPlatformOrderId())));
|
||||
platformOrderIdUpdateResponse.addSuccess(po.getPlatformOrderId());
|
||||
}
|
||||
platformOrderService.updateBatchById(platformOrders);
|
||||
}
|
||||
if(!platformOrderIds.isEmpty()) {
|
||||
log.error("Platform orders not found: {}", platformOrderIds);
|
||||
platformOrderIdUpdateMap.put("fail", platformOrderIds);
|
||||
platformOrderIdUpdateResponse.getFailures().addAll(platformOrderIds);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -11,7 +11,6 @@ import freemarker.template.TemplateException;
|
|||
import io.swagger.annotations.Api;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.shiro.SecurityUtils;
|
||||
import org.jeecg.common.api.dto.message.TemplateMessageDTO;
|
||||
import org.jeecg.common.api.vo.Result;
|
||||
import org.jeecg.common.system.api.ISysBaseAPI;
|
||||
import org.jeecg.common.system.query.QueryGenerator;
|
||||
|
@ -626,18 +625,53 @@ public class InvoiceController {
|
|||
@RequestParam("type") String type
|
||||
) 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);
|
||||
List<FactureDetail> invoiceDetails = shippingInvoiceService.getInvoiceDetailByShopsAndPeriod(shopIds, startDate, endDate, type);
|
||||
boolean isEmployee = securityService.checkIsEmployee();
|
||||
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;
|
||||
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")
|
||||
public byte[] downloadInvoiceInventory(@RequestParam("invoiceCode") String invoiceCode, @RequestParam("internalCode") String internalCode, @RequestParam("invoiceEntity") String invoiceEntity) throws IOException {
|
||||
InvoiceMetaData metaData = new InvoiceMetaData("", invoiceCode, internalCode, invoiceEntity, "");
|
||||
List<SkuOrderPage> skuOrderPages = skuService.getInventoryByInvoiceNumber(metaData.getInvoiceCode());
|
||||
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")
|
||||
public byte[] downloadInventory(@RequestParam("invoiceCode") String invoiceCode, @RequestParam("internalCode") String internalCode, @RequestParam("invoiceEntity") String invoiceEntity) throws IOException {
|
||||
InvoiceMetaData metaData = new InvoiceMetaData("", invoiceCode, internalCode, invoiceEntity, "");
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -8,19 +8,23 @@ import java.util.function.Function;
|
|||
|
||||
public class AddPurchaseOrderRequestBody implements RequestBody {
|
||||
private String providerName;
|
||||
private String employeeName;
|
||||
private String content;
|
||||
private List<SkuStockData> stockData;
|
||||
private final String employeeName;
|
||||
private final String content;
|
||||
private final List<SkuStockData> stockData;
|
||||
|
||||
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) {
|
||||
this.stockData = stockData;
|
||||
this.providerName = providerName;
|
||||
setProviderName(providerName);
|
||||
this.employeeName = employeeName;
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
public void setProviderName(String providerName) {
|
||||
this.providerName = providerName == null || providerName.isEmpty() ? TEMPORARY_PROVIDER_NAME : providerName;
|
||||
}
|
||||
@Override
|
||||
public String api() {
|
||||
return "pur-do-add-purchase";
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -715,6 +715,7 @@
|
|||
) AS shipping_available,
|
||||
MIN(
|
||||
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 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
|
||||
|
|
|
@ -107,7 +107,7 @@
|
|||
JOIN client c ON s.owner_id = c.id
|
||||
JOIN client_category cc ON c.client_category_id = cc.id
|
||||
WHERE po.erp_status IN (1,2)
|
||||
AND cc.name = 'self-service'
|
||||
AND cc.name IN ('self-service', 'confirmed')
|
||||
AND po.order_time >= #{start}
|
||||
ORDER BY po.order_time
|
||||
),
|
||||
|
|
|
@ -85,6 +85,8 @@ public class PlatformOrderShippingInvoiceService {
|
|||
@Autowired
|
||||
private IShopService shopService;
|
||||
@Autowired
|
||||
private ISkuService skuService;
|
||||
@Autowired
|
||||
CountryService countryService;
|
||||
@Autowired
|
||||
IPurchaseOrderService purchaseOrderService;
|
||||
|
@ -791,6 +793,10 @@ public class PlatformOrderShippingInvoiceService {
|
|||
log.info("File asked is of type invoice detail");
|
||||
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()) {
|
||||
log.error("NO INVOICE FILE FOUND : " + invoiceNumber);
|
||||
log.info("Generating a new invoice file ...");
|
||||
|
@ -803,6 +809,11 @@ public class PlatformOrderShippingInvoiceService {
|
|||
List<ExtraFeeResult> extraFees = extraFeeService.findByInvoiceNumber(invoiceNumber);
|
||||
exportToExcel(details, refunds, extraFees, invoiceNumber, client.getInvoiceEntity(), client.getInternalCode());
|
||||
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 {
|
||||
return "ERROR";
|
||||
|
|
Loading…
Reference in New Issue