| | |
| | | import com.ruoyi.basic.service.StorageBlobService; |
| | | import com.ruoyi.common.utils.StringUtils; |
| | | import com.ruoyi.framework.security.LoginUser; |
| | | import com.ruoyi.framework.web.domain.AjaxResult; |
| | | import com.ruoyi.framework.web.domain.R; |
| | | import com.ruoyi.purchase.dto.PurchaseLedgerDto; |
| | | import com.ruoyi.purchase.dto.PurchaseReturnOrderDto; |
| | | import com.ruoyi.purchase.pojo.PaymentRegistration; |
| | |
| | | import com.ruoyi.purchase.service.PurchaseReturnOrdersService; |
| | | import com.ruoyi.sales.pojo.SalesLedgerProduct; |
| | | import dev.langchain4j.data.image.Image; |
| | | import dev.langchain4j.data.message.AiMessage; |
| | | import dev.langchain4j.data.message.ChatMessage; |
| | | import dev.langchain4j.data.message.Content; |
| | | import dev.langchain4j.data.message.ImageContent; |
| | | import dev.langchain4j.data.message.SystemMessage; |
| | | import dev.langchain4j.data.message.TextContent; |
| | | import dev.langchain4j.data.message.UserMessage; |
| | | import dev.langchain4j.data.message.*; |
| | | import dev.langchain4j.model.chat.StreamingChatLanguageModel; |
| | | import dev.langchain4j.model.chat.response.ChatResponse; |
| | | import dev.langchain4j.model.chat.response.StreamingChatResponseHandler; |
| | |
| | | import java.io.InputStream; |
| | | import java.math.BigDecimal; |
| | | import java.math.RoundingMode; |
| | | import java.util.Base64; |
| | | import java.util.Arrays; |
| | | import java.nio.file.Files; |
| | | import java.time.LocalDate; |
| | | import java.time.ZoneId; |
| | | import java.time.format.DateTimeFormatter; |
| | | import java.time.format.DateTimeParseException; |
| | | import java.util.ArrayList; |
| | | import java.util.Collections; |
| | | import java.util.Date; |
| | | import java.util.LinkedHashMap; |
| | | import java.util.List; |
| | | import java.util.Locale; |
| | | import java.util.Map; |
| | | import java.util.NoSuchElementException; |
| | | import java.util.UUID; |
| | | import java.nio.file.Files; |
| | | import java.util.*; |
| | | |
| | | @Service |
| | | public class PurchaseAiService { |
| | |
| | | .doOnError(ex -> aiChatSessionService.refreshSessionStats(finalMemoryId, loginUser)); |
| | | } |
| | | |
| | | public AjaxResult confirmAnalyzeResult(PurchaseAiConfirmRequest request) { |
| | | public R confirmAnalyzeResult(PurchaseAiConfirmRequest request) { |
| | | if (request == null || !StringUtils.hasText(request.getBusinessType())) { |
| | | return AjaxResult.error("businessType不能为空"); |
| | | return R.fail("businessType不能为空"); |
| | | } |
| | | if (request.getPayload() == null || request.getPayload().isEmpty()) { |
| | | return AjaxResult.error("payload不能为空"); |
| | | return R.fail("payload不能为空"); |
| | | } |
| | | |
| | | try { |
| | |
| | | case "purchase_ledger" -> processPurchaseLedger(request.getPayload()); |
| | | case "payment_registration" -> processPaymentRegistration(request.getPayload()); |
| | | case "purchase_return_order" -> processPurchaseReturnOrder(request.getPayload()); |
| | | default -> AjaxResult.error("暂不支持该业务类型: " + businessType); |
| | | default -> R.fail("暂不支持该业务类型: " + businessType); |
| | | }; |
| | | } catch (Exception ex) { |
| | | return AjaxResult.error(toCustomerMessage(ex)); |
| | | return R.fail(toCustomerMessage(ex)); |
| | | } |
| | | } |
| | | |
| | |
| | | 输出要求: |
| | | 1. 只输出合法 JSON,不要 Markdown,不要额外解释。 |
| | | 2. JSON 顶层字段固定为: |
| | | - success: boolean |
| | | - ok: boolean |
| | | - businessType: purchase_ledger | payment_registration | purchase_return_order | unknown |
| | | - action: confirm_required |
| | | - description: 中文说明 |
| | |
| | | """.formatted(message, fileContent); |
| | | } |
| | | |
| | | private AjaxResult processPurchaseLedger(Map<String, Object> payload) throws Exception { |
| | | private R processPurchaseLedger(Map<String, Object> payload) throws Exception { |
| | | if (payload.containsKey("purchaseLedgers")) { |
| | | return processPurchaseLedgerBatch(payload); |
| | | } |
| | | |
| | | Map<String, Object> normalizedPayload = normalizePurchaseLedgerMap(payload); |
| | | PurchaseLedgerDto dto = objectMapper.convertValue(normalizedPayload, PurchaseLedgerDto.class); |
| | | AjaxResult ledgerResult = validatePurchaseLedger(dto, 0); |
| | | R ledgerResult = validatePurchaseLedger(dto, 0); |
| | | if (ledgerResult != null) { |
| | | return ledgerResult; |
| | | } |
| | | AjaxResult supplierResult = fillSupplierIdByName(dto); |
| | | R supplierResult = fillSupplierIdByName(dto); |
| | | if (supplierResult != null) { |
| | | return supplierResult; |
| | | } |
| | | AjaxResult productResult = validatePurchaseProducts(dto.getProductData(), 0); |
| | | R productResult = validatePurchaseProducts(dto.getProductData(), 0); |
| | | if (productResult != null) { |
| | | return productResult; |
| | | } |
| | | int result = purchaseLedgerService.addOrEditPurchase(dto); |
| | | return AjaxResult.success("采购台账已处理", result); |
| | | return R.ok( result,"采购台账已处理"); |
| | | } |
| | | |
| | | private AjaxResult processPurchaseLedgerBatch(Map<String, Object> payload) throws Exception { |
| | | private R processPurchaseLedgerBatch(Map<String, Object> payload) throws Exception { |
| | | List<Map<String, Object>> purchaseLedgers = toMapList(payload.get("purchaseLedgers")); |
| | | if (purchaseLedgers.isEmpty()) { |
| | | return AjaxResult.error("purchaseLedgers不能为空"); |
| | | return R.fail("purchaseLedgers不能为空"); |
| | | } |
| | | |
| | | List<Map<String, Object>> topLevelProductData = toMapList(payload.get("productData")); |
| | |
| | | for (int i = 0; i < purchaseLedgers.size(); i++) { |
| | | Map<String, Object> ledgerMap = normalizePurchaseLedgerMap(purchaseLedgers.get(i)); |
| | | PurchaseLedgerDto dto = objectMapper.convertValue(ledgerMap, PurchaseLedgerDto.class); |
| | | AjaxResult ledgerResult = validatePurchaseLedger(dto, i); |
| | | R ledgerResult = validatePurchaseLedger(dto, i); |
| | | if (ledgerResult != null) { |
| | | return ledgerResult; |
| | | } |
| | | AjaxResult supplierResult = fillSupplierIdByName(dto); |
| | | R supplierResult = fillSupplierIdByName(dto); |
| | | if (supplierResult != null) { |
| | | return supplierResult; |
| | | } |
| | |
| | | products = matchProductsForLedger(ledgerMap, dto, topLevelProductData, purchaseLedgers.size() == 1); |
| | | dto.setProductData(products); |
| | | } |
| | | AjaxResult productResult = validatePurchaseProducts(products, i); |
| | | R productResult = validatePurchaseProducts(products, i); |
| | | if (productResult != null) { |
| | | return productResult; |
| | | } |
| | |
| | | item.put("result", result); |
| | | results.add(item); |
| | | } |
| | | return AjaxResult.success("采购台账已批量处理", results); |
| | | return R.ok( results,"采购台账已批量处理"); |
| | | } |
| | | |
| | | private List<SalesLedgerProduct> matchProductsForLedger(Map<String, Object> ledgerMap, |
| | |
| | | } |
| | | } |
| | | |
| | | private AjaxResult validatePurchaseProducts(List<SalesLedgerProduct> products, int ledgerIndex) { |
| | | private R validatePurchaseProducts(List<SalesLedgerProduct> products, int ledgerIndex) { |
| | | if (products == null || products.isEmpty()) { |
| | | return null; |
| | | } |
| | |
| | | SalesLedgerProduct product = products.get(i); |
| | | String prefix = "第" + (ledgerIndex + 1) + "个采购台账的第" + (i + 1) + "条产品"; |
| | | if (!StringUtils.hasText(product.getProductCategory())) { |
| | | return AjaxResult.error(prefix + "缺少产品名称,请补充后再确认"); |
| | | return R.fail(prefix + "缺少产品名称,请补充后再确认"); |
| | | } |
| | | if (!StringUtils.hasText(product.getSpecificationModel())) { |
| | | return AjaxResult.error(prefix + "缺少规格型号,请补充后再确认"); |
| | | return R.fail(prefix + "缺少规格型号,请补充后再确认"); |
| | | } |
| | | if (!StringUtils.hasText(product.getUnit())) { |
| | | return AjaxResult.error(prefix + "缺少单位,请补充后再确认"); |
| | | return R.fail(prefix + "缺少单位,请补充后再确认"); |
| | | } |
| | | if (product.getQuantity() == null) { |
| | | return AjaxResult.error(prefix + "缺少数量"); |
| | | return R.fail(prefix + "缺少数量"); |
| | | } |
| | | if (product.getTaxInclusiveUnitPrice() == null) { |
| | | return AjaxResult.error(prefix + "缺少含税单价,请补充后再确认"); |
| | | return R.fail(prefix + "缺少含税单价,请补充后再确认"); |
| | | } |
| | | if (product.getTaxInclusiveTotalPrice() == null) { |
| | | return AjaxResult.error(prefix + "缺少含税总价,请补充后再确认"); |
| | | return R.fail(prefix + "缺少含税总价,请补充后再确认"); |
| | | } |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | private AjaxResult validatePurchaseLedger(PurchaseLedgerDto dto, int ledgerIndex) { |
| | | private R validatePurchaseLedger(PurchaseLedgerDto dto, int ledgerIndex) { |
| | | String prefix = "第" + (ledgerIndex + 1) + "个采购台账"; |
| | | if (!StringUtils.hasText(dto.getPurchaseContractNumber())) { |
| | | return AjaxResult.error(prefix + "缺少采购合同号,请补充后再确认"); |
| | | return R.fail(prefix + "缺少采购合同号,请补充后再确认"); |
| | | } |
| | | if (dto.getSupplierId() == null && !StringUtils.hasText(dto.getSupplierName())) { |
| | | return AjaxResult.error(prefix + "缺少供应商名称,请补充后再确认"); |
| | | return R.fail(prefix + "缺少供应商名称,请补充后再确认"); |
| | | } |
| | | return null; |
| | | } |
| | |
| | | return "处理失败:" + message; |
| | | } |
| | | |
| | | private AjaxResult fillSupplierIdByName(PurchaseLedgerDto dto) { |
| | | private R fillSupplierIdByName(PurchaseLedgerDto dto) { |
| | | if (dto.getSupplierId() != null) { |
| | | return null; |
| | | } |
| | | if (!StringUtils.hasText(dto.getSupplierName())) { |
| | | return AjaxResult.error("供应商ID不能为空;未识别到供应商名称,无法自动匹配供应商ID"); |
| | | return R.fail("供应商ID不能为空;未识别到供应商名称,无法自动匹配供应商ID"); |
| | | } |
| | | |
| | | SupplierManage supplier = supplierManageMapper.selectOne(new LambdaQueryWrapper<SupplierManage>() |
| | | .eq(SupplierManage::getSupplierName, dto.getSupplierName().trim()) |
| | | .last("limit 1")); |
| | | if (supplier == null) { |
| | | return AjaxResult.error("未找到供应商:" + dto.getSupplierName() + ",请先维护供应商或手动选择供应商ID"); |
| | | return R.fail("未找到供应商:" + dto.getSupplierName() + ",请先维护供应商或手动选择供应商ID"); |
| | | } |
| | | dto.setSupplierId(supplier.getId()); |
| | | return null; |
| | | } |
| | | |
| | | private AjaxResult processPaymentRegistration(Map<String, Object> payload) { |
| | | private R processPaymentRegistration(Map<String, Object> payload) { |
| | | Object recordsValue = payload.get("records"); |
| | | List<PaymentRegistration> records; |
| | | if (recordsValue == null) { |
| | |
| | | }); |
| | | } |
| | | int result = paymentRegistrationService.insertPaymentRegistration(records); |
| | | return AjaxResult.success("付款登记已处理", result); |
| | | return R.ok( result,"付款登记已处理"); |
| | | } |
| | | |
| | | private AjaxResult processPurchaseReturnOrder(Map<String, Object> payload) { |
| | | private R processPurchaseReturnOrder(Map<String, Object> payload) { |
| | | PurchaseReturnOrderDto dto = objectMapper.convertValue(payload, PurchaseReturnOrderDto.class); |
| | | Boolean result = purchaseReturnOrdersService.add(dto); |
| | | return AjaxResult.success("采购退货单已处理", result); |
| | | return R.ok( result,"采购退货单已处理"); |
| | | } |
| | | } |