package jnpf.dmsService;
|
|
import jnpf.base.ActionResult;
|
import jnpf.base.BillRuleApi;
|
import jnpf.dmsEntity.fenfa.*;
|
import jnpf.dmsMapper.DmsWenjianDayinJishuMapper;
|
import jnpf.exception.DataException;
|
import lombok.RequiredArgsConstructor;
|
import org.springframework.stereotype.Service;
|
import org.springframework.transaction.annotation.Propagation;
|
import org.springframework.transaction.annotation.Transactional;
|
import java.time.ZoneId;
|
import java.time.ZonedDateTime;
|
import java.util.*;
|
|
@Service
|
@RequiredArgsConstructor
|
public class DmsWenjianDayinHaomaService {
|
private final DmsWenjianDayinJishuMapper mapper;
|
private final BillRuleApi billRuleApi;
|
|
/** 调用方持有任务行锁;新任务创建同事务取号,旧任务仅补齐尚未打印的份号。 */
|
@Transactional(propagation = Propagation.MANDATORY, rollbackFor = Exception.class)
|
public List<DmsWenjianDayinHaoma> ensureTaskNumbers(String tenant, DmsWenjianDayinRenwuEntity task, int consumed) {
|
if (task == null || task.getId() == null || task.getDayinFenshu() == null
|
|| task.getDayinFenshu() < 1 || consumed < 0 || consumed > task.getDayinFenshu())
|
throw new DataException("打印任务份数或已消耗序号无效");
|
List<DmsWenjianDayinHaoma> saved = mapper.selectTaskNumbers(tenant, task.getId());
|
if (!saved.isEmpty()) {
|
validateSaved(task, consumed, saved);
|
return saved;
|
}
|
int remaining = task.getDayinFenshu() - consumed;
|
if (remaining <= 0) return saved;
|
List<DmsWenjianDayinHaoma> allocated = reserve(tenant, task, remaining);
|
for (int i = 0; i < allocated.size(); i++) {
|
DmsWenjianDayinHaoma number = allocated.get(i);
|
number.setId(UUID.randomUUID().toString()); number.setTaskSequence(consumed + i + 1);
|
if (mapper.insertTaskNumber(tenant, task.getId(), number) != 1) throw new DataException("保存任务固定份号失败");
|
}
|
return allocated;
|
}
|
|
/** 回传仅验证既有固定号码,绝不在确认阶段补号。 */
|
public void requireReservedNumbers(String tenant, DmsWenjianDayinRenwuEntity task,
|
int consumed, List<DmsWenjianDayinHaoma> frozen) {
|
List<DmsWenjianDayinHaoma> saved = mapper.selectTaskNumbers(tenant, task.getId());
|
validateSaved(task, consumed, saved);
|
List<DmsWenjianDayinHaoma> expected = saved.stream()
|
.filter(number -> number.getTaskSequence() > consumed).limit(frozen.size()).toList();
|
if (!expected.equals(frozen)) throw new DataException("回传号码与任务固定份号不一致");
|
}
|
|
private void validateSaved(DmsWenjianDayinRenwuEntity task, int consumed,
|
List<DmsWenjianDayinHaoma> saved) {
|
int total = task.getDayinFenshu();
|
if (saved.isEmpty() || saved.size() > total) throw new DataException("任务固定份号缺失");
|
int first = total - saved.size() + 1;
|
if (first > consumed + 1) throw new DataException("任务固定份号不完整");
|
Set<String> unique = new HashSet<>();
|
for (int i = 0; i < saved.size(); i++) {
|
DmsWenjianDayinHaoma number = saved.get(i);
|
if (number == null || !Objects.equals(number.getTaskSequence(), first + i)
|
|| number.getId() == null || number.getCounterId() == null
|
|| number.getYear() == null || number.getSequence() == null
|
|| number.getSequence() < 1 || number.getSequence() > 9999
|
|| number.getSerialNumber() == null || number.getSerialNumber().isBlank()
|
|| !unique.add(number.getSerialNumber())
|
|| !String.format(Locale.ROOT, "%04d%04d", number.getYear(), number.getSequence()).equals(number.getCountSerialNumber()))
|
throw new DataException("任务固定份号不完整或已损坏,不能重新取号");
|
}
|
}
|
|
/** 必须与任务创建/首次旧任务补号处于同一事务。已提交的号码永不回收。 */
|
@Transactional(propagation = Propagation.MANDATORY, rollbackFor = Exception.class)
|
public List<DmsWenjianDayinHaoma> reserve(String tenant, DmsWenjianDayinRenwuEntity task, int copies) {
|
if (copies < 1 || copies > 9999 || task.getWenjianBianhao() == null || task.getWenjianBianhao().isBlank()
|
|| task.getBanbenhao() == null || task.getBanbenhao().isBlank()) throw new DataException("打印计数组或份数无效");
|
int year = ZonedDateTime.now(ZoneId.of("Asia/Shanghai")).getYear();
|
DmsWenjianDayinJishu counter = mapper.reserve(UUID.randomUUID().toString(), tenant,
|
task.getWenjianBianhao(), task.getBanbenhao(), year, copies);
|
if (counter == null) throw new DataException("该文件版本本年度计数流水已超过9999,不能继续取号");
|
List<DmsWenjianDayinHaoma> numbers = new ArrayList<>();
|
for (int i = counter.getValue() - copies + 1; i <= counter.getValue(); i++) {
|
ActionResult<String> result = billRuleApi.getBillNumber("wenjianDayinLiushuihao");
|
if (result == null || result.getData() == null || result.getData().isBlank()) throw new DataException("打印唯一流水取号失败");
|
DmsWenjianDayinHaoma number = new DmsWenjianDayinHaoma();
|
number.setCounterId(counter.getId()); number.setYear(year); number.setSequence(i);
|
number.setSerialNumber(result.getData());
|
number.setCountSerialNumber(String.format(Locale.ROOT, "%04d%04d", year, i));
|
numbers.add(number);
|
}
|
return numbers;
|
}
|
}
|