mirror of https://github.com/jeecgboot/jeecg-boot
feat: client cancel invoice
parent
67b1a94360
commit
6fe8ffea92
|
@ -11,7 +11,9 @@ SELECT combined.id,
|
|||
shipping_fee,
|
||||
purchase_fee,
|
||||
amount,
|
||||
currency.code AS currency
|
||||
currency.code AS currency,
|
||||
ordered,
|
||||
status
|
||||
FROM (
|
||||
SELECT id,
|
||||
create_by,
|
||||
|
@ -25,7 +27,9 @@ FROM (
|
|||
NULL AS shipping_fee,
|
||||
NULL AS purchase_fee,
|
||||
amount,
|
||||
currency_id
|
||||
currency_id,
|
||||
null AS ordered,
|
||||
status
|
||||
FROM credit
|
||||
UNION ALL
|
||||
SELECT id,
|
||||
|
@ -40,7 +44,9 @@ FROM (
|
|||
total_amount AS shipping_fee,
|
||||
pt.total AS purchase_fee,
|
||||
COALESCE(pt.total + si.total_amount, si.total_amount) AS amount,
|
||||
currency_id
|
||||
currency_id,
|
||||
null AS ordered,
|
||||
status
|
||||
FROM shipping_invoice si
|
||||
LEFT JOIN (
|
||||
SELECT po.shipping_invoice_number, SUM(poc.purchase_fee) AS total
|
||||
|
@ -65,7 +71,9 @@ FROM (
|
|||
NULL AS shipping_fee,
|
||||
final_amount AS purchase_fee,
|
||||
final_amount AS amount,
|
||||
currency_id
|
||||
currency_id,
|
||||
ordered,
|
||||
status
|
||||
FROM purchase_order
|
||||
WHERE invoice_number LIKE '%-%-1%'
|
||||
AND client_id IS NOT NULL
|
||||
|
|
|
@ -203,7 +203,7 @@ public class CreditController extends JeecgController<Credit, ICreditService> {
|
|||
if(!credit.getId().equals(latestCredit.getId())) {
|
||||
return Result.error(409, "Credit cannot be deleted, unless it's the last record.");
|
||||
}
|
||||
invoiceService.cancelInvoice(credit.getId(), credit.getInvoiceNumber(), credit.getClientId());
|
||||
invoiceService.cancelInvoice(credit.getId(), credit.getInvoiceNumber(), credit.getClientId(), true);
|
||||
return Result.OK("sys.api.entryDeleteSuccess");
|
||||
}
|
||||
|
||||
|
@ -340,6 +340,7 @@ public class CreditController extends JeecgController<Credit, ICreditService> {
|
|||
}
|
||||
invoiceDatas.setInvoiceNumber(credit.getInvoiceNumber());
|
||||
invoiceDatas.setDescription(credit.getDescription());
|
||||
invoiceDatas.setStatus(credit.getStatus());
|
||||
return Result.OK(invoiceDatas);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,15 +5,17 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
|
|||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import io.swagger.annotations.Api;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.http.HttpStatus;
|
||||
import org.jeecg.common.api.vo.Result;
|
||||
import org.jeecg.common.system.query.QueryGenerator;
|
||||
import org.jeecg.modules.business.entity.Client;
|
||||
import org.jeecg.modules.business.entity.Invoice;
|
||||
import org.jeecg.modules.business.service.*;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
|
||||
@Api(tags = "发票")
|
||||
@RestController
|
||||
|
@ -22,19 +24,59 @@ import java.util.List;
|
|||
public class InvoiceViewController {
|
||||
@Autowired
|
||||
private InvoiceService invoiceService;
|
||||
@Autowired
|
||||
private IClientService clientService;
|
||||
@Autowired
|
||||
private ISecurityService securityService;
|
||||
|
||||
@GetMapping(value = "/list")
|
||||
public Result<?> list(Invoice invoice, @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
|
||||
@RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
|
||||
HttpServletRequest req) {
|
||||
QueryWrapper<Invoice> queryWrapper = QueryGenerator.initQueryWrapper(invoice, req.getParameterMap());
|
||||
boolean isEmployee = securityService.checkIsEmployee();
|
||||
Map<String, String[]> parameterMap = new HashMap<>(req.getParameterMap());
|
||||
for(String key : req.getParameterMap().keySet()) {
|
||||
if(key.equals("clientId") && !isEmployee) {
|
||||
parameterMap.remove("clientId");
|
||||
}
|
||||
if(key.equals("createBy") && !isEmployee) {
|
||||
parameterMap.remove("createBy");
|
||||
}
|
||||
}
|
||||
if(!isEmployee) {
|
||||
Client currentClient = clientService.getCurrentClient();
|
||||
if (currentClient == null) {
|
||||
return Result.error(HttpStatus.SC_UNAUTHORIZED, "Client is not registered as a user");
|
||||
}
|
||||
parameterMap.put("clientId", new String[]{currentClient.getId()});
|
||||
}
|
||||
QueryWrapper<Invoice> queryWrapper = QueryGenerator.initQueryWrapper(invoice, parameterMap);
|
||||
Page<Invoice> page = new Page<>(pageNo, pageSize);
|
||||
IPage<Invoice> pageList = invoiceService.page(page, queryWrapper);
|
||||
return Result.ok(pageList);
|
||||
}
|
||||
@DeleteMapping(value = "/cancelInvoice")
|
||||
public Result<?> cancelInvoice(@RequestParam("id") String id, @RequestParam("invoiceNumber") String invoiceNumber, @RequestParam("clientId") String clientId) {
|
||||
boolean isEmployee = securityService.checkIsEmployee();
|
||||
Client client = clientService.getById(clientId);
|
||||
Client currentClient;
|
||||
if(client == null) {
|
||||
log.error("Client {} not found", clientId);
|
||||
return Result.error(HttpStatus.SC_NOT_FOUND, "Client not found");
|
||||
}
|
||||
if (!isEmployee) {
|
||||
currentClient = clientService.getCurrentClient();
|
||||
if (currentClient == null) {
|
||||
log.error("Client is not registered as a user : {}", clientId);
|
||||
return Result.error(HttpStatus.SC_UNAUTHORIZED, "Client is not registered as a user");
|
||||
}
|
||||
if(!clientId.equals(currentClient.getId())) {
|
||||
log.error("Client {} is not authorized to download invoice detail for client {}", currentClient.getInternalCode(), client.getInternalCode());
|
||||
return Result.error(HttpStatus.SC_NOT_FOUND, "Invoice not found");
|
||||
}
|
||||
}
|
||||
log.info("Cancelling invoice number : {}", invoiceNumber);
|
||||
boolean invoiceCancelled = invoiceService.cancelInvoice(id, invoiceNumber, clientId);
|
||||
boolean invoiceCancelled = invoiceService.cancelInvoice(id, invoiceNumber, clientId, isEmployee);
|
||||
return Result.ok(invoiceCancelled ? "sys.api.invoiceCancelSuccess" : "sys.api.invoiceCancelSuccessFileDeleteFail");
|
||||
}
|
||||
@DeleteMapping(value="/cancelBatchInvoice")
|
||||
|
|
|
@ -328,7 +328,7 @@ public class InvoiceController {
|
|||
try {
|
||||
List<SkuQuantity> skuQuantities = skuService.getSkuQuantitiesFromOrderIds(param.orderIds());
|
||||
if(skuQuantities.isEmpty()) {
|
||||
return Result.error("Nothing to invoice.");
|
||||
return Result.error(404, "Nothing to invoice.");
|
||||
}
|
||||
String purchaseId = purchaseOrderService.addPurchase(skuQuantities ,param.orderIds());
|
||||
metaData = purchaseOrderService.makeInvoice(purchaseId);
|
||||
|
@ -1142,6 +1142,7 @@ public class InvoiceController {
|
|||
invoiceDatas.setInsuranceFee(insuranceFee);
|
||||
invoiceDatas.setFeeAndQtyPerCountry(feeAndQtyPerCountry);
|
||||
invoiceDatas.setExtraFees(extraFeesMap);
|
||||
invoiceDatas.setStatus(invoice.getStatus());
|
||||
|
||||
return Result.OK(invoiceDatas);
|
||||
}
|
||||
|
@ -1153,12 +1154,15 @@ public class InvoiceController {
|
|||
InvoiceDatas invoiceDatas = new InvoiceDatas();
|
||||
|
||||
List<PurchaseOrder> invoices = purchaseOrderService.getPurchasesByInvoiceNumber(invoiceNumber);
|
||||
int invoiceStatus = 1;
|
||||
if(invoices == null) {
|
||||
return Result.error("No data for product found.");
|
||||
}
|
||||
List<PurchaseInvoiceEntry> invoiceData = new ArrayList<>();
|
||||
for(PurchaseOrder order : invoices) {
|
||||
invoiceData.addAll(purchaseOrderContentMapper.selectInvoiceDataByID(order.getId()));
|
||||
if(order.getStatus() == 0)
|
||||
invoiceStatus = 0;
|
||||
}
|
||||
List<BigDecimal> refundList = iSavRefundService.getRefundAmount(invoiceNumber);
|
||||
Map<String, Fee> feeAndQtyPerSku = new HashMap<>(); // it maps number of order and purchase fee per item : <France,<250, 50.30>>, <UK, <10, 2.15>>
|
||||
|
@ -1205,7 +1209,7 @@ public class InvoiceController {
|
|||
invoiceDatas.setRefund(refund);
|
||||
invoiceDatas.setFinalAmountEur(invoices.stream().map(PurchaseOrder::getFinalAmount).reduce(BigDecimal.ZERO, BigDecimal::add));
|
||||
invoiceDatas.setFeeAndQtyPerSku(feeAndQtyPerSku);
|
||||
|
||||
invoiceDatas.setStatus(invoiceStatus);
|
||||
return Result.OK(invoiceDatas);
|
||||
}
|
||||
public String countryNameFormatting(String country) {
|
||||
|
|
|
@ -37,7 +37,8 @@ public class InvoiceDatas {
|
|||
private BigDecimal finalAmount;
|
||||
@JSONField(name = "extraFees")
|
||||
private Map<String, Fee> extraFees;
|
||||
|
||||
@JSONField(name = "status")
|
||||
private Integer status;
|
||||
}
|
||||
@Data
|
||||
@Builder
|
||||
|
|
|
@ -105,4 +105,16 @@ public class Transaction implements Serializable {
|
|||
@Excel(name = "currency", width = 15)
|
||||
@ApiModelProperty(value = "currency")
|
||||
private java.lang.String currency;
|
||||
/**
|
||||
* 0: cancelled, 1: normal (default)
|
||||
*/
|
||||
@Excel(name = "status", width = 15)
|
||||
@ApiModelProperty(value = "status")
|
||||
private java.lang.Integer status;
|
||||
/**
|
||||
* 0: not ordered, 1: ordered
|
||||
*/
|
||||
@Excel(name = "ordered", width = 15)
|
||||
@ApiModelProperty(value = "ordered")
|
||||
private java.lang.Integer ordered;
|
||||
}
|
||||
|
|
|
@ -256,7 +256,7 @@ public interface PlatformOrderMapper extends BaseMapper<PlatformOrder> {
|
|||
@Param("start") String startDate, @Param("end") String endDate,
|
||||
@Param("order") String order, @Param("column") String column,
|
||||
@Param("offset") Integer offset, @Param("size") Integer pageSize);
|
||||
void selectBatchIdsForUpdate(@Param("ids") List<String> orderIds);
|
||||
List<PlatformOrder> selectBatchIdsForUpdate(@Param("ids") List<String> orderIds);
|
||||
@MapKey("id")
|
||||
Map<String, PlatformOrder> selectBatchUninvoicedIdsForUpdate(@Param("ids") List<String> orderIds);
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
WHERE invoice_number = #{invoiceNumber}
|
||||
</select>
|
||||
<select id="fetchShippingInvoice" resultType="org.jeecg.modules.business.entity.ShippingInvoice">
|
||||
SELECT id, total_amount, discount_amount, final_amount, paid_amount, currency_id, client_id, create_time
|
||||
SELECT id, total_amount, discount_amount, final_amount, paid_amount, currency_id, client_id, create_time, status
|
||||
FROM shipping_invoice s
|
||||
WHERE s.invoice_number = #{invoiceNumber}
|
||||
</select>
|
||||
|
|
|
@ -129,15 +129,17 @@
|
|||
|
||||
<select id="getSkuQuantitiesFromOrderIds" resultType="org.jeecg.modules.business.vo.SkuQuantity">
|
||||
SELECT sku_id as ID, sku.erp_code as erp_code, SUM(quantity) AS quantity
|
||||
FROM platform_order_content
|
||||
JOIN sku ON platform_order_content.sku_id = sku.id
|
||||
WHERE platform_order_id IN
|
||||
FROM platform_order_content poc
|
||||
JOIN sku ON poc.sku_id = sku.id
|
||||
JOIN platform_order po ON poc.platform_order_id = po.id
|
||||
WHERE poc.platform_order_id IN
|
||||
<foreach collection="orderIds" separator="," open="(" close=")" index="index" item="orderId">
|
||||
#{orderId}
|
||||
</foreach>
|
||||
AND erp_status IN ('1','2','3')
|
||||
AND product_available = 0
|
||||
AND virtual_product_available = 0
|
||||
AND poc.erp_status IN ('1','2','3')
|
||||
AND poc.product_available = 0
|
||||
AND poc.virtual_product_available = 0
|
||||
AND po.purchase_invoice_number IS NULL
|
||||
GROUP BY sku_id;
|
||||
</select>
|
||||
<select id="countAllSkus" resultType="java.lang.Integer">
|
||||
|
|
|
@ -6,7 +6,7 @@ import org.jeecg.modules.business.entity.Invoice;
|
|||
import java.util.List;
|
||||
|
||||
public interface InvoiceService extends IService<Invoice> {
|
||||
boolean cancelInvoice(String id, String invoiceNumber, String clientId);
|
||||
boolean cancelInvoice(String id, String invoiceNumber, String clientId, boolean isEmployee);
|
||||
|
||||
boolean cancelBatchInvoice(List<Invoice> invoices);
|
||||
}
|
||||
|
|
|
@ -12,6 +12,8 @@ import org.springframework.stereotype.Service;
|
|||
import java.io.File;
|
||||
import java.math.BigDecimal;
|
||||
import java.nio.file.Path;
|
||||
import java.time.LocalDate;
|
||||
import java.util.Calendar;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
@ -48,6 +50,8 @@ public class InvoiceServiceImpl extends ServiceImpl<InvoiceMapper, Invoice> impl
|
|||
@Value("${jeecg.path.shippingInvoiceDetailDir}")
|
||||
private String SHIPPING_INVOICE_DETAIL_LOCATION;
|
||||
|
||||
private final int CANCEL_DAYS_LIMIT = 14;
|
||||
|
||||
/**
|
||||
* Cancel invoice and deletes generated files.
|
||||
* shipping : cancels shipping_invoice by setting status to 0, resets data in platform_order_content, platform_order, sav_refund, and balance
|
||||
|
@ -60,7 +64,7 @@ public class InvoiceServiceImpl extends ServiceImpl<InvoiceMapper, Invoice> impl
|
|||
* @return if invoice is successfully cancelled and files are deleted, will return false even when some files are just missing
|
||||
*/
|
||||
@Override
|
||||
public boolean cancelInvoice(String id, String invoiceNumber, String clientId) {
|
||||
public boolean cancelInvoice(String id, String invoiceNumber, String clientId, boolean isEmployee) {
|
||||
String operationType = Balance.OperationType.DebitCancellation.name();
|
||||
String originalOperationType = Balance.OperationType.Debit.name();
|
||||
BigDecimal amount = BigDecimal.ZERO;
|
||||
|
@ -80,6 +84,16 @@ public class InvoiceServiceImpl extends ServiceImpl<InvoiceMapper, Invoice> impl
|
|||
log.error("Purchase order already cancelled : {}", id);
|
||||
return false;
|
||||
}
|
||||
LocalDate orderDate = po.getCreateTime().toInstant().atZone(Calendar.getInstance().getTimeZone().toZoneId()).toLocalDate();
|
||||
LocalDate twoWeeksAgo = LocalDate.now().minusDays(CANCEL_DAYS_LIMIT);
|
||||
if(!isEmployee && orderDate.isBefore(twoWeeksAgo)) {
|
||||
log.error("Purchase order {} is older than {}, client is not allowed cancel it", invoiceNumber, CANCEL_DAYS_LIMIT);
|
||||
return false;
|
||||
}
|
||||
if(!isEmployee && po.isOrdered()) {
|
||||
log.error("Purchase order {} is already ordered, cannot be cancelled", invoiceNumber);
|
||||
return false;
|
||||
}
|
||||
currencyId = po.getCurrencyId();
|
||||
if (po.getInventoryDocumentString() != null && !po.getInventoryDocumentString().isEmpty())
|
||||
shippingInvoiceService.deleteAttachmentFile(po.getInventoryDocumentString());
|
||||
|
@ -99,6 +113,12 @@ public class InvoiceServiceImpl extends ServiceImpl<InvoiceMapper, Invoice> impl
|
|||
log.error("Shipping invoice already cancelled : {}", id);
|
||||
return false;
|
||||
}
|
||||
LocalDate orderDate = si.getCreateTime().toInstant().atZone(Calendar.getInstance().getTimeZone().toZoneId()).toLocalDate();
|
||||
LocalDate twoWeeksAgo = LocalDate.now().minusDays(CANCEL_DAYS_LIMIT);
|
||||
if(!isEmployee && orderDate.isBefore(twoWeeksAgo)) {
|
||||
log.error("Shipping invoice {} is older than {}, client is not allowed to cancel it", invoiceNumber, CANCEL_DAYS_LIMIT);
|
||||
return false;
|
||||
}
|
||||
platformOrderContentService.cancelInvoice(invoiceNumber, clientId);
|
||||
platformOrderService.cancelInvoice(invoiceNumber, clientId);
|
||||
shippingInvoiceService.cancelInvoice(id);
|
||||
|
@ -114,7 +134,17 @@ public class InvoiceServiceImpl extends ServiceImpl<InvoiceMapper, Invoice> impl
|
|||
return false;
|
||||
}
|
||||
if(shippingInvoice.getStatus() == ShippingInvoice.Status.Cancelled.getCode()) {
|
||||
log.error("Complete invoice already cancelled : {}", id);
|
||||
log.error("Complete invoice already cancelled : {}", invoiceNumber);
|
||||
return false;
|
||||
}
|
||||
LocalDate orderDate = shippingInvoice.getCreateTime().toInstant().atZone(Calendar.getInstance().getTimeZone().toZoneId()).toLocalDate();
|
||||
LocalDate twoWeeksAgo = LocalDate.now().minusDays(CANCEL_DAYS_LIMIT);
|
||||
if(!isEmployee && orderDate.isBefore(twoWeeksAgo)) {
|
||||
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.getInventoryDocumentString() != null && !purchase.getInventoryDocumentString().isEmpty())
|
||||
|
|
Loading…
Reference in New Issue