| | |
| | | import com.ruoyi.basic.vo.CustomerVo; |
| | | import com.ruoyi.common.utils.SecurityUtils; |
| | | import com.ruoyi.framework.security.LoginUser; |
| | | import com.ruoyi.sales.dto.InvoiceLedgerDto; |
| | | import com.ruoyi.sales.mapper.InvoiceLedgerMapper; |
| | | import com.ruoyi.sales.mapper.ReceiptPaymentMapper; |
| | | import com.ruoyi.sales.mapper.SalesLedgerMapper; |
| | | import com.ruoyi.sales.mapper.SalesQuotationMapper; |
| | | import com.ruoyi.sales.mapper.ShippingInfoMapper; |
| | | import com.ruoyi.sales.pojo.ReceiptPayment; |
| | | import com.ruoyi.sales.pojo.SalesLedger; |
| | | import com.ruoyi.sales.pojo.SalesQuotation; |
| | | import com.ruoyi.sales.pojo.ShippingInfo; |
| | |
| | | import java.time.YearMonth; |
| | | import java.time.ZoneId; |
| | | import java.time.format.DateTimeFormatter; |
| | | import java.util.ArrayList; |
| | | import java.util.Comparator; |
| | | import java.util.Date; |
| | | import java.util.HashMap; |
| | | import java.util.LinkedHashMap; |
| | | import java.util.LinkedList; |
| | | import java.util.List; |
| | | import java.util.Locale; |
| | | import java.util.Map; |
| | | import java.util.Objects; |
| | | import java.util.*; |
| | | import java.util.regex.Matcher; |
| | | import java.util.regex.Pattern; |
| | | import java.util.stream.Collectors; |
| | |
| | | private final SalesLedgerMapper salesLedgerMapper; |
| | | private final SalesQuotationMapper salesQuotationMapper; |
| | | private final ShippingInfoMapper shippingInfoMapper; |
| | | private final ReceiptPaymentMapper receiptPaymentMapper; |
| | | private final InvoiceLedgerMapper invoiceLedgerMapper; |
| | | private final SalesReceiptReturnMapper salesReceiptReturnMapper; |
| | | private final AiSessionUserContext aiSessionUserContext; |
| | | |
| | |
| | | SalesLedgerMapper salesLedgerMapper, |
| | | SalesQuotationMapper salesQuotationMapper, |
| | | ShippingInfoMapper shippingInfoMapper, |
| | | ReceiptPaymentMapper receiptPaymentMapper, |
| | | InvoiceLedgerMapper invoiceLedgerMapper, |
| | | SalesReceiptReturnMapper salesReceiptReturnMapper, |
| | | AiSessionUserContext aiSessionUserContext) { |
| | | this.customerMapper = customerMapper; |
| | | this.salesLedgerMapper = salesLedgerMapper; |
| | | this.salesQuotationMapper = salesQuotationMapper; |
| | | this.shippingInfoMapper = shippingInfoMapper; |
| | | this.receiptPaymentMapper = receiptPaymentMapper; |
| | | this.invoiceLedgerMapper = invoiceLedgerMapper; |
| | | this.salesReceiptReturnMapper = salesReceiptReturnMapper; |
| | | this.aiSessionUserContext = aiSessionUserContext; |
| | | } |
| | |
| | | @P(value = "返回条数,默认10,最大30", required = false) Integer limit) { |
| | | LoginUser loginUser = currentLoginUser(memoryId); |
| | | DateRange range = resolveDateRange(startDate, endDate, null); |
| | | LambdaQueryWrapper<ReceiptPayment> wrapper = new LambdaQueryWrapper<>(); |
| | | applyTenantFilter(wrapper, loginUser.getTenantId(), ReceiptPayment::getTenantId); |
| | | applyDeptFilter(wrapper, loginUser.getCurrentDeptId(), ReceiptPayment::getDeptId); |
| | | wrapper.ge(ReceiptPayment::getReceiptPaymentDate, range.start()) |
| | | .le(ReceiptPayment::getReceiptPaymentDate, range.end()) |
| | | .orderByDesc(ReceiptPayment::getReceiptPaymentDate, ReceiptPayment::getId); |
| | | List<ReceiptPayment> payments = defaultList(receiptPaymentMapper.selectList(wrapper)); |
| | | if (payments.isEmpty()) { |
| | | return jsonResponse(true, "sales_customer_interaction_list", "未查询到客户往来记录", rangeSummary(range, 0, keyword), Map.of("items", List.of()), Map.of()); |
| | | } |
| | | // LambdaQueryWrapper<ReceiptPayment> wrapper = new LambdaQueryWrapper<>(); |
| | | // applyTenantFilter(wrapper, loginUser.getTenantId(), ReceiptPayment::getTenantId); |
| | | // applyDeptFilter(wrapper, loginUser.getCurrentDeptId(), ReceiptPayment::getDeptId); |
| | | // wrapper.ge(ReceiptPayment::getReceiptPaymentDate, range.start()) |
| | | // .le(ReceiptPayment::getReceiptPaymentDate, range.end()) |
| | | // .orderByDesc(ReceiptPayment::getReceiptPaymentDate, ReceiptPayment::getId); |
| | | // List<ReceiptPayment> payments = defaultList(receiptPaymentMapper.selectList(wrapper)); |
| | | // if (payments.isEmpty()) { |
| | | // return jsonResponse(true, "sales_customer_interaction_list", "未查询到客户往来记录", rangeSummary(range, 0, keyword), Map.of("items", List.of()), Map.of()); |
| | | // } |
| | | // |
| | | // List<Long> ledgerIds = payments.stream() |
| | | // .map(ReceiptPayment::getSalesLedgerId) |
| | | // .filter(Objects::nonNull) |
| | | // .distinct() |
| | | // .collect(Collectors.toList()); |
| | | // Map<Long, SalesLedger> ledgerMap = defaultList(salesLedgerMapper.selectBatchIds(ledgerIds)).stream() |
| | | // .filter(ledger -> tenantMatched(ledger.getTenantId(), loginUser.getTenantId())) |
| | | // .collect(Collectors.toMap(SalesLedger::getId, item -> item, (a, b) -> a, LinkedHashMap::new)); |
| | | // |
| | | // List<ReceiptPayment> filtered = payments.stream() |
| | | // .filter(item -> matchInteractionKeyword(item, ledgerMap.get(item.getSalesLedgerId()), keyword)) |
| | | // .limit(normalizeLimit(limit)) |
| | | // .collect(Collectors.toList()); |
| | | // |
| | | // BigDecimal totalReceiptAmount = filtered.stream() |
| | | // .map(ReceiptPayment::getReceiptPaymentAmount) |
| | | // .filter(Objects::nonNull) |
| | | // .reduce(BigDecimal.ZERO, BigDecimal::add); |
| | | |
| | | List<Long> ledgerIds = payments.stream() |
| | | .map(ReceiptPayment::getSalesLedgerId) |
| | | .filter(Objects::nonNull) |
| | | .distinct() |
| | | .collect(Collectors.toList()); |
| | | Map<Long, SalesLedger> ledgerMap = defaultList(salesLedgerMapper.selectBatchIds(ledgerIds)).stream() |
| | | .filter(ledger -> tenantMatched(ledger.getTenantId(), loginUser.getTenantId())) |
| | | .collect(Collectors.toMap(SalesLedger::getId, item -> item, (a, b) -> a, LinkedHashMap::new)); |
| | | // List<Map<String, Object>> items = filtered.stream().map(item -> { |
| | | // SalesLedger ledger = ledgerMap.get(item.getSalesLedgerId()); |
| | | // Map<String, Object> map = new LinkedHashMap<>(); |
| | | // map.put("id", item.getId()); |
| | | // map.put("salesLedgerId", item.getSalesLedgerId()); |
| | | // map.put("salesContractNo", ledger == null ? "" : safe(ledger.getSalesContractNo())); |
| | | // map.put("customerName", ledger == null ? "" : safe(ledger.getCustomerName())); |
| | | // map.put("projectName", ledger == null ? "" : safe(ledger.getProjectName())); |
| | | // map.put("receiptPaymentDate", formatDate(item.getReceiptPaymentDate())); |
| | | // map.put("receiptPaymentAmount", item.getReceiptPaymentAmount()); |
| | | // map.put("receiptPaymentType", safe(item.getReceiptPaymentType())); |
| | | // map.put("registrant", safe(item.getRegistrant())); |
| | | // return map; |
| | | // }).collect(Collectors.toList()); |
| | | |
| | | List<ReceiptPayment> filtered = payments.stream() |
| | | .filter(item -> matchInteractionKeyword(item, ledgerMap.get(item.getSalesLedgerId()), keyword)) |
| | | .limit(normalizeLimit(limit)) |
| | | .collect(Collectors.toList()); |
| | | |
| | | BigDecimal totalReceiptAmount = filtered.stream() |
| | | .map(ReceiptPayment::getReceiptPaymentAmount) |
| | | .filter(Objects::nonNull) |
| | | .reduce(BigDecimal.ZERO, BigDecimal::add); |
| | | |
| | | List<Map<String, Object>> items = filtered.stream().map(item -> { |
| | | SalesLedger ledger = ledgerMap.get(item.getSalesLedgerId()); |
| | | Map<String, Object> map = new LinkedHashMap<>(); |
| | | map.put("id", item.getId()); |
| | | map.put("salesLedgerId", item.getSalesLedgerId()); |
| | | map.put("salesContractNo", ledger == null ? "" : safe(ledger.getSalesContractNo())); |
| | | map.put("customerName", ledger == null ? "" : safe(ledger.getCustomerName())); |
| | | map.put("projectName", ledger == null ? "" : safe(ledger.getProjectName())); |
| | | map.put("receiptPaymentDate", formatDate(item.getReceiptPaymentDate())); |
| | | map.put("receiptPaymentAmount", item.getReceiptPaymentAmount()); |
| | | map.put("receiptPaymentType", safe(item.getReceiptPaymentType())); |
| | | map.put("registrant", safe(item.getRegistrant())); |
| | | return map; |
| | | }).collect(Collectors.toList()); |
| | | |
| | | Map<String, Object> summary = rangeSummary(range, items.size(), keyword); |
| | | summary.put("totalReceiptAmount", totalReceiptAmount); |
| | | summary.put("customerCount", items.stream().map(item -> String.valueOf(item.get("customerName"))).filter(StringUtils::hasText).distinct().count()); |
| | | return jsonResponse(true, "sales_customer_interaction_list", "已返回客户往来明细", summary, Map.of("items", items), Map.of()); |
| | | // Map<String, Object> summary = rangeSummary(range, items.size(), keyword); |
| | | // summary.put("totalReceiptAmount", totalReceiptAmount); |
| | | // summary.put("customerCount", items.stream().map(item -> String.valueOf(item.get("customerName"))).filter(StringUtils::hasText).distinct().count()); |
| | | // return jsonResponse(true, "sales_customer_interaction_list", "已返回客户往来明细", summary, Map.of("items", items), Map.of()); |
| | | return jsonResponse(true, "sales_customer_interaction_list", "已返回客户往来明细", null, Map.of("items", List.of()), Map.of()); |
| | | } |
| | | |
| | | @Tool(name = "查询发货台账", value = "按关键词和时间范围查询发货台账") |
| | |
| | | List<SalesLedger> ledgers = querySalesLedgers(loginUser, range); |
| | | List<SalesQuotation> quotations = querySalesQuotations(loginUser, range); |
| | | List<ShippingInfo> shippings = queryShippings(loginUser, range); |
| | | List<ReceiptPayment> receipts = queryReceipts(loginUser, range); |
| | | |
| | | |
| | | BigDecimal contractAmountTotal = ledgers.stream() |
| | | .map(SalesLedger::getContractAmount) |
| | |
| | | .map(SalesQuotation::getTotalAmount) |
| | | .filter(Objects::nonNull) |
| | | .reduce(BigDecimal.ZERO, BigDecimal::add); |
| | | BigDecimal receivedAmountTotal = receipts.stream() |
| | | .map(ReceiptPayment::getReceiptPaymentAmount) |
| | | .filter(Objects::nonNull) |
| | | .reduce(BigDecimal.ZERO, BigDecimal::add); |
| | | BigDecimal pendingAmountTotal = maxZero(contractAmountTotal.subtract(receivedAmountTotal)); |
| | | |
| | | long shippingCount = shippings.size(); |
| | | long shippedCount = shippings.stream().filter(item -> isShippedStatus(item.getStatus())).count(); |
| | |
| | | summary.put("shipRate", shipRate); |
| | | summary.put("contractAmountTotal", contractAmountTotal); |
| | | summary.put("quotationAmountTotal", quotationAmountTotal); |
| | | summary.put("receivedAmountTotal", receivedAmountTotal); |
| | | summary.put("pendingAmountTotal", pendingAmountTotal); |
| | | summary.put("receivedAmountTotal", BigDecimal.ZERO); |
| | | summary.put("pendingAmountTotal", BigDecimal.ZERO); |
| | | |
| | | Map<String, Object> charts = new LinkedHashMap<>(); |
| | | charts.put("amountBarOption", buildAmountBarOption(contractAmountTotal, quotationAmountTotal, receivedAmountTotal, pendingAmountTotal)); |
| | | // charts.put("amountBarOption", buildAmountBarOption(contractAmountTotal, quotationAmountTotal, receivedAmountTotal, pendingAmountTotal)); |
| | | charts.put("amountBarOption", buildAmountBarOption(contractAmountTotal, quotationAmountTotal, BigDecimal.ONE, BigDecimal.ONE)); |
| | | charts.put("shippingPieOption", buildShippingPieOption(shippedCount, Math.max(shippingCount - shippedCount, 0))); |
| | | charts.put("customerTopBarOption", buildCustomerTopBarOption(topCustomers)); |
| | | charts.put("contractTrendLineOption", buildContractTrendLineOption(trendData.labels(), trendData.values())); |
| | |
| | | return defaultList(shippingInfoMapper.selectList(wrapper)); |
| | | } |
| | | |
| | | private List<ReceiptPayment> queryReceipts(LoginUser loginUser, DateRange range) { |
| | | LambdaQueryWrapper<ReceiptPayment> wrapper = new LambdaQueryWrapper<>(); |
| | | applyTenantFilter(wrapper, loginUser.getTenantId(), ReceiptPayment::getTenantId); |
| | | applyDeptFilter(wrapper, loginUser.getCurrentDeptId(), ReceiptPayment::getDeptId); |
| | | if (range != null) { |
| | | wrapper.ge(ReceiptPayment::getReceiptPaymentDate, range.start()) |
| | | .le(ReceiptPayment::getReceiptPaymentDate, range.end()); |
| | | } |
| | | return defaultList(receiptPaymentMapper.selectList(wrapper)); |
| | | } |
| | | |
| | | private List<ReceiptPayment> queryReceiptsByLedgerIds(LoginUser loginUser, List<Long> ledgerIds) { |
| | | if (ledgerIds == null || ledgerIds.isEmpty()) { |
| | | return List.of(); |
| | | } |
| | | LambdaQueryWrapper<ReceiptPayment> wrapper = new LambdaQueryWrapper<>(); |
| | | applyTenantFilter(wrapper, loginUser.getTenantId(), ReceiptPayment::getTenantId); |
| | | applyDeptFilter(wrapper, loginUser.getCurrentDeptId(), ReceiptPayment::getDeptId); |
| | | wrapper.in(ReceiptPayment::getSalesLedgerId, ledgerIds); |
| | | return defaultList(receiptPaymentMapper.selectList(wrapper)); |
| | | } |
| | | |
| | | private List<ShippingInfo> queryShippingsByLedgerIds(LoginUser loginUser, List<Long> ledgerIds) { |
| | | if (ledgerIds == null || ledgerIds.isEmpty()) { |
| | | return List.of(); |
| | |
| | | return Map.of(); |
| | | } |
| | | Map<Long, BigDecimal> result = new HashMap<>(); |
| | | for (InvoiceLedgerDto item : defaultList(invoiceLedgerMapper.invoicedTotal(ledgerIds))) { |
| | | if (item.getSalesLedgerId() == null) { |
| | | continue; |
| | | } |
| | | result.merge(item.getSalesLedgerId().longValue(), defaultDecimal(item.getInvoiceTotal()), BigDecimal::add); |
| | | } |
| | | // for (InvoiceLedgerDto item : defaultList(invoiceLedgerMapper.invoicedTotal(ledgerIds))) { |
| | | // if (item.getSalesLedgerId() == null) { |
| | | // continue; |
| | | // } |
| | | // result.merge(item.getSalesLedgerId().longValue(), defaultDecimal(item.getInvoiceTotal()), BigDecimal::add); |
| | | // } |
| | | return result; |
| | | } |
| | | |
| | | private Map<Long, BigDecimal> sumReceiptAmounts(LoginUser loginUser, List<Long> ledgerIds) { |
| | | Map<Long, BigDecimal> result = new HashMap<>(); |
| | | for (ReceiptPayment item : queryReceiptsByLedgerIds(loginUser, ledgerIds)) { |
| | | if (item.getSalesLedgerId() == null) { |
| | | continue; |
| | | } |
| | | result.merge(item.getSalesLedgerId(), defaultDecimal(item.getReceiptPaymentAmount()), BigDecimal::add); |
| | | } |
| | | |
| | | return result; |
| | | } |
| | | |
| | |
| | | || safe(customer.getContactPhone()).contains(text) |
| | | || safe(customer.getCompanyPhone()).contains(text) |
| | | || safe(customer.getUsageUserName()).contains(text); |
| | | } |
| | | |
| | | private boolean matchInteractionKeyword(ReceiptPayment payment, SalesLedger ledger, String keyword) { |
| | | if (!StringUtils.hasText(keyword)) { |
| | | return true; |
| | | } |
| | | String text = keyword.trim(); |
| | | return safe(payment.getRegistrant()).contains(text) |
| | | || (ledger != null && (safe(ledger.getCustomerName()).contains(text) |
| | | || safe(ledger.getSalesContractNo()).contains(text) |
| | | || safe(ledger.getProjectName()).contains(text))); |
| | | } |
| | | |
| | | private boolean matchLedgerCustomerKeyword(SalesLedger ledger, String keyword) { |