| | |
| | | @Override |
| | | public void saveStorageAttachment(List<StorageAttachment> attachments, Long recordId, StorageAttachmentRecordType recordType, String fileType) { |
| | | // 删除旧图 |
| | | deleteStorageAttachment(new StorageAttachment(fileType, (long) recordType.ordinal(), recordId)); |
| | | // deleteStorageAttachment(new StorageAttachment(fileType, (long) recordType.ordinal(), recordId)); |
| | | for (StorageAttachment attachment : attachments) { |
| | | // 获取关联记录 |
| | | StorageBlob storageBlob = attachment.getStorageBlobDTO(); |
| | |
| | | |
| | | @ApiModelProperty(value = "记录创建时间") |
| | | @TableField(fill = com.baomidou.mybatisplus.annotation.FieldFill.INSERT) |
| | | @JsonFormat(pattern = "yyyy-MM-dd") |
| | | @DateTimeFormat(pattern = "yyyy-MM-dd") |
| | | // @JsonFormat(pattern = "yyyy-MM-dd") |
| | | // @DateTimeFormat(pattern = "yyyy-MM-dd") |
| | | private LocalDateTime createTime; |
| | | |
| | | @ApiModelProperty(value = "最后修改该记录的用户") |
| | |
| | | * 更新已有任务 |
| | | */ |
| | | public void rescheduleTimingTask(TimingTask task) throws SchedulerException { |
| | | TriggerKey triggerKey = new TriggerKey("trigger_" + task.getId()); |
| | | TriggerKey triggerKey = new TriggerKey("trigger_" + task.getId(), "TIMING_TASK_TRIGGER_GROUP"); |
| | | |
| | | // 获取现有触发器并转换为 CronTrigger |
| | | Trigger oldTrigger = scheduler.getTrigger(triggerKey); |
| | |
| | | throw new SchedulerException("Existing trigger is not a CronTrigger"); |
| | | } |
| | | |
| | | // 构建新触发器 |
| | | Trigger newTrigger = TriggerBuilder.newTrigger() |
| | | .withIdentity(triggerKey) |
| | | .withDescription(task.getTaskName()) |
| | | .withSchedule(CronScheduleBuilder.cronSchedule(convertToCronExpression(task))) |
| | | .startAt(Date.from(task.getNextExecutionTime().atZone(ZoneId.systemDefault()).toInstant())) |
| | | .forJob(oldTrigger.getJobKey()) |
| | | // 3. 构建CronTrigger,确保持久化配置 |
| | | CronTrigger newTrigger = TriggerBuilder.newTrigger() |
| | | .withIdentity(triggerKey) // 唯一标识,用于持久化存储 |
| | | .withDescription(task.getTaskName() + "_TRIGGER") // 触发器描述 |
| | | .forJob(oldTrigger.getJobKey()) // 关联对应的Job |
| | | .withSchedule(CronScheduleBuilder |
| | | .cronSchedule(convertToCronExpression(task)) // 错过执行时的策略(根据业务调整) |
| | | ) |
| | | // 4. 设置开始时间(若为null则立即生效) |
| | | .startAt(task.getNextExecutionTime() != null |
| | | ? Date.from(task.getNextExecutionTime().atZone(ZoneId.systemDefault()).toInstant()) |
| | | : new Date()) |
| | | .build(); |
| | | |
| | | // 构建新触发器 |
| | | // Trigger newTrigger = TriggerBuilder.newTrigger() |
| | | // .withIdentity(triggerKey) |
| | | // .withDescription(task.getTaskName()) |
| | | // .withSchedule(CronScheduleBuilder.cronSchedule(convertToCronExpression(task))) |
| | | // .startAt(Date.from(task.getNextExecutionTime().atZone(ZoneId.systemDefault()).toInstant())) |
| | | // .forJob(oldTrigger.getJobKey()) |
| | | // .build(); |
| | | |
| | | scheduler.rescheduleJob(triggerKey, newTrigger); |
| | | } |
| | |
| | | } |
| | | |
| | | private JobDetail buildJobDetail(TimingTask task) { |
| | | JobDataMap jobDataMap = new JobDataMap(); |
| | | jobDataMap.put("taskId", task.getId()); |
| | | // 1. 构建唯一JobKey(基于任务ID,确保重启后能识别) |
| | | JobKey jobKey = new JobKey("timingTask_" + task.getId(), "TIMING_TASK_GROUP"); |
| | | |
| | | // 2. 封装任务数据(仅使用基本类型,确保可序列化) |
| | | JobDataMap jobDataMap = new JobDataMap(); |
| | | jobDataMap.put("taskId", task.getId()); // 任务ID(Long,可序列化) |
| | | jobDataMap.put("taskName", task.getTaskName()); // 任务名称(String,可序列化) |
| | | jobDataMap.put("taskType", task.getFrequencyType()); // 任务类型(String) |
| | | // 按需添加其他必要的基本类型参数 |
| | | |
| | | // 3. 构建JobDetail,设置持久化相关属性 |
| | | return JobBuilder.newJob(TimingTaskJob.class) |
| | | .withIdentity("timingTask_" + task.getId()) |
| | | .withDescription(task.getTaskName()) |
| | | .usingJobData(jobDataMap) |
| | | .storeDurably() |
| | | .withIdentity(jobKey) // 唯一标识,用于持久化存储 |
| | | .withDescription(task.getTaskName()) // 任务描述,存入数据库 |
| | | .usingJobData(jobDataMap) // 绑定任务数据 |
| | | .storeDurably() // 即使没有触发器关联也持久化保存 |
| | | .requestRecovery(true) // 当调度器崩溃后恢复时,重新执行未完成的任务 |
| | | .build(); |
| | | } |
| | | |
| | | private Trigger buildJobTrigger(TimingTask task, JobDetail jobDetail) { |
| | | // 1. 构建唯一TriggerKey(基于任务ID) |
| | | TriggerKey triggerKey = new TriggerKey("trigger_" + task.getId(), "TIMING_TASK_TRIGGER_GROUP"); |
| | | |
| | | // 2. 生成Cron表达式(原逻辑不变) |
| | | String cronExpression = convertToCronExpression(task); |
| | | |
| | | TriggerBuilder<CronTrigger> triggerBuilder = TriggerBuilder.newTrigger() |
| | | .withIdentity("trigger_" + task.getId()) |
| | | .withDescription(task.getTaskName()) |
| | | .withSchedule(CronScheduleBuilder.cronSchedule(cronExpression)); |
| | | |
| | | if (jobDetail != null) { |
| | | triggerBuilder.forJob(jobDetail); |
| | | } |
| | | |
| | | if (task.getNextExecutionTime() != null) { |
| | | triggerBuilder.startAt(Date.from(task.getNextExecutionTime().atZone(ZoneId.systemDefault()).toInstant())); |
| | | } |
| | | |
| | | return triggerBuilder.build(); |
| | | // 3. 构建CronTrigger,确保持久化配置 |
| | | CronTrigger trigger = TriggerBuilder.newTrigger() |
| | | .withIdentity(triggerKey) // 唯一标识,用于持久化存储 |
| | | .withDescription(task.getTaskName() + "_TRIGGER") // 触发器描述 |
| | | .forJob(jobDetail) // 关联对应的Job |
| | | .withSchedule(CronScheduleBuilder |
| | | .cronSchedule(cronExpression) |
| | | .withMisfireHandlingInstructionDoNothing() // 错过执行时的策略(根据业务调整) |
| | | ) |
| | | // 4. 设置开始时间(若为null则立即生效) |
| | | .startAt(task.getNextExecutionTime() != null |
| | | ? Date.from(task.getNextExecutionTime().atZone(ZoneId.systemDefault()).toInstant()) |
| | | : new Date()) |
| | | .build(); |
| | | return trigger; |
| | | } |
| | | private String convertToCronExpression(TimingTask task) { |
| | | // 参数校验 |
| | |
| | | } |
| | | } |
| | | |
| | | @Scheduled(cron = "0 0 3 * * ?") // 每天凌晨3点执行 |
| | | // @Scheduled(cron = "0 0 3 * * ?") // 每天凌晨3点执行 |
| | | public void cleanupExpiredTempFiles() { |
| | | LambdaQueryWrapper<TempFile> wrapper = new LambdaQueryWrapper<>(); |
| | | wrapper.lt(TempFile::getExpireTime, LocalDateTime.now()); // expireTime < 当前时间 |
| | |
| | | import com.baomidou.mybatisplus.annotation.TableField; |
| | | import com.baomidou.mybatisplus.annotation.TableName; |
| | | import com.fasterxml.jackson.annotation.JsonFormat; |
| | | import com.ruoyi.framework.aspectj.lang.annotation.Excel; |
| | | import com.ruoyi.purchase.pojo.TicketRegistration; |
| | | import com.ruoyi.sales.pojo.CommonFile; |
| | | import com.ruoyi.sales.pojo.SalesLedgerProduct; |
| | |
| | | private String salesContractNo; |
| | | |
| | | /** |
| | | * 开票日期 |
| | | */ |
| | | |
| | | @JsonFormat(pattern = "yyyy-MM-dd") |
| | | @DateTimeFormat(pattern = "yyyy-MM-dd") |
| | | private LocalDate entryDate; |
| | | |
| | | /** |
| | | * 客户名称 |
| | | */ |
| | | private String customerName; |
| | |
| | | |
| | | @JsonFormat(pattern = "yyyy-MM-dd") |
| | | @DateTimeFormat(pattern = "yyyy-MM-dd") |
| | | @TableField(exist = false) |
| | | private LocalDate enterDate; |
| | | |
| | | /** |
| | |
| | | if(ObjectUtils.isNotEmpty(loginUser) && null != loginUser.getTenantId()) { |
| | | purchaseLedger.setTenantId(loginUser.getTenantId()); |
| | | } |
| | | purchaseLedger.setSalesContractNo(ObjectUtils.isNotEmpty(salesLedger) ? salesLedger.getSalesContractNo() : null); |
| | | purchaseLedger.setSalesContractNo(ObjectUtils.isNotEmpty(salesLedger) ? salesLedger.getSalesContractNo() : ""); |
| | | purchaseLedger.setSalesLedgerId(ObjectUtils.isNotEmpty(salesLedger) ? salesLedger.getId() : -1); |
| | | purchaseLedger.setSupplierName(supplierManage.getSupplierName()); |
| | | purchaseLedger.setRecorderId(purchaseLedgerDto.getRecorderId()); |
| | | purchaseLedger.setRecorderName(sysUser.getNickName()); |
| | |
| | | BeanUtils.copyProperties(ticketRegistrationDto, ticketRegistration); |
| | | ticketRegistration.setPurchaseContractNumber(purchaseLedger.getPurchaseContractNumber()); |
| | | ticketRegistration.setTenantId(purchaseLedger.getTenantId()); |
| | | ticketRegistration.setIssueDate(ticketRegistrationDto.getIssueDate()); |
| | | ticketRegistration.setIssueDate(ticketRegistrationDto.getEntryDate()); |
| | | ticketRegistration.setContractAmount(purchaseLedger.getContractAmount()); |
| | | ticketRegistration.setSalesLedgerId(purchaseLedger.getSalesLedgerId()); |
| | | ticketRegistration.setEnterDate(ticketRegistrationDto.getEnterDate()); |
| | |
| | | @Override |
| | | public IPage<ReceiptPaymentDto> bindInvoiceNoRegPage(Page page, ReceiptPaymentDto receiptPaymentDto) { |
| | | IPage<ReceiptPaymentDto> receiptPaymentDtoIPage = receiptPaymentMapper.bindInvoiceNoRegPage(page, receiptPaymentDto); |
| | | if (receiptPaymentDto.getStatus()) { |
| | | receiptPaymentDtoIPage.getRecords().removeIf(receiptPaymentDto1 -> new BigDecimal("0.00").equals(receiptPaymentDto1.getNoReceiptAmount())); |
| | | } |
| | | // if (receiptPaymentDto.getStatus()) { |
| | | // long count = receiptPaymentDtoIPage.getRecords() |
| | | // .stream() |
| | | // .filter(receiptPaymentDto1 -> new BigDecimal("0.00").equals(receiptPaymentDto1.getNoReceiptAmount())) |
| | | // .count(); |
| | | // receiptPaymentDtoIPage |
| | | // .getRecords() |
| | | // .removeIf(receiptPaymentDto1 -> new BigDecimal("0.00").equals(receiptPaymentDto1.getNoReceiptAmount())); |
| | | // receiptPaymentDtoIPage.setTotal(receiptPaymentDtoIPage.getTotal() - count); |
| | | // } |
| | | receiptPaymentDtoIPage.getRecords().forEach(item -> { |
| | | // 比较回款金额 == 待回款金额 |
| | | if (item.getInvoiceTotal().compareTo(item.getReceiptPaymentAmountTotal()) == 0) { |
| | |
| | | redis: |
| | | # 地址 |
| | | host: 127.0.0.1 |
| | | # host: 172.17.0.1 |
| | | # host: 172.17.0.1 |
| | | # 端口,默认为6379 |
| | | port: 6379 |
| | | # 数据库索引 |
| | | database: 0 |
| | | # 密码 |
| | | # password: root2022! |
| | | # password: root2022! |
| | | password: |
| | | |
| | | # 连接超时时间 |
| | |
| | | max-active: 8 |
| | | # #连接池最大阻塞等待时间(使用负值表示没有限制) |
| | | max-wait: -1ms |
| | | # Quartz定时任务配置(新增部分) |
| | | quartz: |
| | | job-store-type: jdbc # 使用数据库存储 |
| | | jdbc: |
| | | initialize-schema: always # 首次运行时自动创建表结构,成功后改为never |
| | | schema: classpath:org/quartz/impl/jdbcjobstore/tables_mysql_innodb.sql # MySQL表结构脚本 |
| | | properties: |
| | | org: |
| | | quartz: |
| | | scheduler: |
| | | instanceName: RuoYiScheduler |
| | | instanceId: AUTO |
| | | jobStore: |
| | | class: org.quartz.impl.jdbcjobstore.JobStoreTX |
| | | driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate # MySQL适配 |
| | | tablePrefix: QRTZ_ # 表名前缀,与脚本一致 |
| | | isClustered: false # 单节点模式(集群需改为true) |
| | | clusterCheckinInterval: 10000 |
| | | txIsolationLevelSerializable: true |
| | | threadPool: |
| | | class: org.quartz.simpl.SimpleThreadPool |
| | | threadCount: 10 # 线程池大小 |
| | | threadPriority: 5 |
| | | makeThreadsDaemons: true |
| | | updateCheck: false # 关闭版本检查 |
| | | |
| | | # token配置 |
| | | token: |
| | |
| | | secret: abcdefghijklmnopqrstuvwxyz |
| | | # 令牌有效期(默认30分钟) |
| | | expireTime: 450 |
| | | |
| | | |
| | | # MyBatis Plus配置 |
| | | mybatis-plus: |
| | | # 搜索指定包别名 根据自己的项目来 |
| | |
| | | enable-sql-runner: true |
| | | db-config: |
| | | id-type: auto |
| | | |
| | | |
| | | # PageHelper分页插件 |
| | | pagehelper: |
| | | helperDialect: mysql |
| | |
| | | excludes: /system/notice |
| | | # 匹配链接 |
| | | urlPatterns: /system/*,/monitor/*,/tool/* |
| | | |
| | | |
| | | # 代码生成 |
| | | gen: |
| | | # 作者 |
| | |
| | | <mapper namespace="com.ruoyi.procurementrecord.mapper.CustomStorageMapper"> |
| | | |
| | | <select id="listPageCopyByCustom" resultType="com.ruoyi.procurementrecord.pojo.CustomStorage"> |
| | | select *, |
| | | sum(inbound_num) as inboundNum, |
| | | sum(inbound_num) as inboundNum0, |
| | | sum(tax_inclusive_total_price) as taxInclusiveTotalPrice |
| | | from custom_storage |
| | | select t1.*, |
| | | sum(t1.inbound_num) as inboundNum, |
| | | sum(t1.inbound_num) as inboundNum0, |
| | | sum(t1.tax_inclusive_total_price) as taxInclusiveTotalPrice, |
| | | SUM(t1.inbound_num) - COALESCE(SUM(t2.inbound_num), 0) AS availableStock |
| | | from custom_storage t1 |
| | | left join procurement_record_out t2 on t1.id = t2.procurement_record_storage_id and t2.type = 3 |
| | | <where> |
| | | <if test="req.productCategory != null and req.productCategory != ''"> |
| | | and product_category like concat('%',#{req.productCategory},'%') |
| | | and t1.product_category like concat('%',#{req.productCategory},'%') |
| | | </if> |
| | | <if test="req.supplierName !=null and req.supplierName != ''"> |
| | | and supplier_name like concat('%',#{req.supplierName},'%') |
| | | and t1.supplier_name like concat('%',#{req.supplierName},'%') |
| | | </if> |
| | | <if test="req.inboundDate !=null"> |
| | | and inbound_date like concat('%',#{req.inboundDate},'%') |
| | | <if test="req.timeStr != null and req.timeStr != ''"> |
| | | and t1.inbound_date like concat('%',#{req.timeStr},'%') |
| | | </if> |
| | | |
| | | </where> |
| | | group by product_category, specification_model, tax_inclusive_unit_price |
| | | order by inbound_date desc |
| | | group by t1.product_category, t1.specification_model, t1.tax_inclusive_unit_price |
| | | HAVING availableStock > 0 |
| | | order by t1.inbound_date desc |
| | | </select> |
| | | </mapper> |
| | |
| | | LEFT JOIN invoice_registration_product pr ON pr.id = il.invoice_registration_product_id |
| | | WHERE il.invoice_no IS NOT NULL |
| | | AND invoice_type = '增专票' |
| | | AND DATE_FORMAT(il.invoice_date, '%Y-%m') IS NOT NULL -- 新增:过滤month为NULL的情 |
| | | GROUP BY DATE_FORMAT(il.invoice_date, '%Y-%m') |
| | | ) a1 |
| | | LEFT JOIN ( |
| | |
| | | LEFT JOIN invoice_registration_product pr ON pr.id = il.invoice_registration_product_id |
| | | WHERE il.invoice_no IS NOT NULL |
| | | AND invoice_type = '增专票' |
| | | AND DATE_FORMAT(il.invoice_date, '%Y-%m') IS NOT NULL -- 新增:过滤month为NULL的情 |
| | | GROUP BY DATE_FORMAT(il.invoice_date, '%Y-%m') |
| | | ) a1 ON a1.month = a2.month |
| | | WHERE a1.month IS NULL |
| | | ORDER BY month |
| | | )as a |
| | | <where> |
| | | a.month is not null |
| | | <if test="month != null"> |
| | | and a.month = #{month} |
| | | </if> |
| | |
| | | sum(pr.tickets_amount)as receipt_payment_amount, |
| | | pl.contract_amount-sum(pr.tickets_amount) AS unReceipt_payment_amount, |
| | | pl.entry_date, |
| | | pl.execution_date, |
| | | pl.recorder_name, |
| | | pl.payment_method |
| | | from purchase_ledger pl |
| | |
| | | |
| | | <select id="bindInvoiceNoRegPage" resultType="com.ruoyi.sales.dto.ReceiptPaymentDto"> |
| | | SELECT |
| | | T1.id , |
| | | T1.invoice_no , |
| | | T1.invoice_total , |
| | | T1.id, |
| | | T1.invoice_no, |
| | | T1.invoice_total, |
| | | T3.project_name, |
| | | T1.invoice_person , |
| | | T1.invoice_date , |
| | | T1.create_time , |
| | | T1.create_user , |
| | | T1.update_time , |
| | | T1.update_user , |
| | | T1.tenant_id , |
| | | T1.invoice_person, |
| | | T1.invoice_date, |
| | | T1.create_time, |
| | | T1.create_user, |
| | | T1.update_time, |
| | | T1.update_user, |
| | | T1.tenant_id, |
| | | T2.tax_rate, |
| | | T3.sales_contract_no, |
| | | T3.customer_contract_no, |
| | | T3.customer_name, |
| | | T4.invoiceFileName, |
| | | T5.product_category, |
| | | IFNULL(T6.receipt_payment_amount_total ,0) AS receipt_payment_amount_total, |
| | | (T1.invoice_total - IFNULL(T6.receipt_payment_amount_total ,0)) AS no_receipt_amount |
| | | IFNULL(T6.receipt_payment_amount_total, 0) AS receipt_payment_amount_total, |
| | | (T1.invoice_total - IFNULL(T6.receipt_payment_amount_total, 0)) AS noReceiptAmount |
| | | FROM invoice_ledger T1 |
| | | LEFT JOIN invoice_registration_product T2 ON T2.id = T1.invoice_registration_product_id |
| | | LEFT JOIN sales_ledger T3 ON T3.id = T2.sales_ledger_id |
| | | LEFT JOIN ( |
| | | SELECT |
| | | invoice_ledger_id, |
| | | GROUP_CONCAT( name ORDER BY id ASC SEPARATOR ' | ') AS invoiceFileName |
| | | FROM invoice_ledger_file GROUP BY invoice_ledger_id |
| | | GROUP_CONCAT(name ORDER BY id ASC SEPARATOR ' | ') AS invoiceFileName |
| | | FROM invoice_ledger_file |
| | | GROUP BY invoice_ledger_id |
| | | ) T4 ON T4.invoice_ledger_id = T1.id |
| | | LEFT JOIN sales_ledger_product T5 ON T2.sales_ledger_product_id = T5.id |
| | | LEFT JOIN ( |
| | | SELECT SUM(receipt_payment_amount) AS receipt_payment_amount_total,invoice_ledger_id FROM receipt_payment GROUP |
| | | BY invoice_ledger_id |
| | | SELECT |
| | | SUM(receipt_payment_amount) AS receipt_payment_amount_total, |
| | | invoice_ledger_id |
| | | FROM receipt_payment |
| | | GROUP BY invoice_ledger_id |
| | | ) T6 ON T1.id = T6.invoice_ledger_id |
| | | <where> |
| | | <if test="req.customerName != null and req.customerName !=''"> |
| | |
| | | AND T1.invoice_date >= DATE_FORMAT(#{req.invoiceDateStart},'%Y-%m-%d') |
| | | </if> |
| | | <if test="req.invoiceDateEnd != null and req.invoiceDateEnd != '' "> |
| | | AND T1.invoice_date <= DATE_FORMAT(#{req.invoiceDateEnd},'%Y-%m-%d') |
| | | AND T1.invoice_date <= DATE_FORMAT(#{req.invoiceDateEnd},'%Y-%m-%d') |
| | | </if> |
| | | <if test="req.status != null and req.status"> |
| | | and (T1.invoice_total - IFNULL(T6.receipt_payment_amount_total, 0)) > 0 |
| | | </if> |
| | | </where> |
| | | ORDER BY T2.create_time DESC |
| | | |
| | | ORDER BY IFNULL(T2.create_time, T1.create_time) DESC |
| | | |
| | | </select> |
| | | |
| | | <select id="invoiceInfo" resultType="com.ruoyi.sales.dto.InvoiceLedgerDto"> |