拆分模块

This commit is contained in:
2025-09-03 20:56:44 +08:00
parent 08cc2c29a5
commit a2f5e4864b
939 changed files with 14227 additions and 9607 deletions

View File

@@ -0,0 +1,68 @@
package com.ecep.contract.ds;
import static com.ecep.contract.AppV2.DEFAULT_DB_DATABASE;
import static com.ecep.contract.AppV2.DEFAULT_DB_HOST;
import static com.ecep.contract.AppV2.DEFAULT_DB_PASSWORD;
import static com.ecep.contract.AppV2.DEFAULT_DB_PORT;
import static com.ecep.contract.AppV2.DEFAULT_DB_USERNAME;
import javax.sql.DataSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.env.Environment;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean;
import org.springframework.data.repository.config.BootstrapMode;
import org.springframework.jdbc.core.JdbcTemplate;
import com.zaxxer.hikari.HikariDataSource;
@Configuration
@EnableJpaRepositories(
basePackages = {"com.ecep.contract.ds"},
bootstrapMode = BootstrapMode.LAZY,
repositoryFactoryBeanClass = JpaRepositoryFactoryBean.class
)
public class DsRepositoriesConfig {
private static final Logger logger = LoggerFactory.getLogger(DsRepositoriesConfig.class);
@Bean
// @ConfigurationProperties(prefix = "spring.datasource")
@Primary
public DataSource dataSource(Environment env) {
if (logger.isDebugEnabled()) {
logger.debug("SpringApp.dataSource, env:{}", env);
}
String host = env.getProperty("db.server.host", DEFAULT_DB_HOST);
String port = env.getProperty("db.server.port", DEFAULT_DB_PORT);
String database = env.getProperty("db.server.database", DEFAULT_DB_DATABASE);
String username = env.getProperty("db.server.username", DEFAULT_DB_USERNAME);
String password = env.getProperty("db.server.password", DEFAULT_DB_PASSWORD);
String url = "jdbc:mysql://" + host + ":" + port + "/" + database;
if (logger.isDebugEnabled()) {
logger.debug("db server url:{},user:{}", url, username);
}
return DataSourceBuilder.create()
.type(HikariDataSource.class)
.url(url)
.username(username)
.password(password)
.driverClassName("com.mysql.cj.jdbc.Driver")
.build();
}
@Primary
@Bean
public JdbcTemplate jdbcTemplate(@Qualifier("dataSource") DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
}

View File

@@ -0,0 +1,26 @@
package com.ecep.contract.ds;
import jakarta.persistence.AttributeConverter;
import jakarta.persistence.Converter;
import java.time.MonthDay;
import java.time.format.DateTimeFormatter;
@Converter(autoApply = true)
public class MonthDayConverter implements AttributeConverter<MonthDay, String> {
// 定义日期格式(月-日,两位数)
private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("MM-dd");
@Override
public String convertToDatabaseColumn(MonthDay attribute) {
// 将 MonthDay 转换为数据库存储的字符串MM-dd
return attribute != null ? attribute.format(FORMATTER) : null;
}
@Override
public MonthDay convertToEntityAttribute(String dbData) {
// 将数据库字符串MM-dd转换为 MonthDay
return dbData != null ? MonthDay.parse(dbData, FORMATTER) : null;
}
}

View File

@@ -0,0 +1,9 @@
package com.ecep.contract.ds;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
public interface MyRepository<T, ID> extends JpaRepository<T, ID>, JpaSpecificationExecutor<T> {
}

View File

@@ -0,0 +1,18 @@
package com.ecep.contract.ds.company;
import com.ecep.contract.ds.company.service.CompanyContactService;
import com.ecep.contract.model.CompanyContact;
import com.ecep.contract.util.EntityStringConverter;
public class CompanyContactStringConverter extends EntityStringConverter<CompanyContact> {
public CompanyContactStringConverter() {
}
public CompanyContactStringConverter(CompanyContactService service) {
setInitialized(employee -> service.findById(employee.getId()));
// setFromString(service::findByName);
}
}

View File

@@ -0,0 +1,181 @@
package com.ecep.contract.ds.company;
import java.io.File;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.ecep.contract.util.FileUtils;
import org.springframework.util.StringUtils;
import com.ecep.contract.CompanyFileType;
import com.ecep.contract.MyDateTimeUtils;
import com.ecep.contract.constant.CloudServiceConstant;
import com.ecep.contract.ds.company.service.CompanyFileService;
import com.ecep.contract.model.CompanyFile;
public class CompanyFileUtils {
public static CompanyFile fillType(String fileName, String companyName, File destDir) {
CompanyFile companyFile = new CompanyFile();
if (isTycReport(fileName, companyName)) {
File dest = new File(destDir, fileName);
companyFile.setType(CompanyFileType.CreditReport);
companyFile.setFilePath(dest.getAbsolutePath());
return companyFile;
}
// 包含公司名称 和 天眼查 的文件
if (fileName.contains(companyName) && fileName.contains(CloudServiceConstant.TYC_NAME)) {
LocalDateTime dateTime = LocalDateTime.now();
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd_HH-mm");
int idx = fileName.indexOf("报告");
String destName = (idx > 0 ? fileName.substring(0, fileName.indexOf("报告") + 2) + "_" : "") +
companyName + "_天眼查_" + dateTime.format(fmt) + "." + StringUtils.getFilenameExtension(fileName);
}
for (CompanyFileType value : CompanyFileType.values()) {
}
return null;
}
/**
* 从文件名判断是否是天眼查的报告文件
*/
public static boolean isTycReport(String fileName, String companyName) {
// 文件名中必须包含 天眼查 字样
if (!fileName.contains(CloudServiceConstant.TYC_NAME)) {
return false;
}
// 文件名中必须包含 公司名称
if (!fileName.contains(companyName)) {
return false;
}
// 文件名后缀需符合要求
return FileUtils.withExtensions(fileName, FileUtils.PDF, FileUtils.DOC, FileUtils.DOCX);
}
public static boolean isCompanyFile(File file) {
String fileName = file.getName();
if (fileName.equals(FileUtils.FILE_DB_JSON)) {
return true;
}
if (fileName.equals(FileUtils.FILE_B1001_JSON)) {
return true;
}
if (fileName.equals(FileUtils.FILE_BLACK_LIST_JSON)) {
return true;
}
if (fileName.equals("合同列表.json")) {
return true;
}
// 营业执照
if (fileName.contains(CompanyFileService.BUSINESS_LICENSE)) {
return true;
}
// 操作证
if (fileName.contains(CompanyFileService.OPERATION_CERTIFICATE)) {
return true;
}
// 许可证
if (fileName.contains(CompanyFileService.PERMIT_CERTIFICATE)) {
return true;
}
// 登记证
if (fileName.contains(CompanyFileService.REGISTRATION_CERTIFICATE)) {
return true;
}
// 组织机构代码证
if (fileName.contains(CompanyFileService.ORGANIZATION_CODE_CERTIFICATE)) {
return true;
}
return false;
}
/**
* 根据文件名中提取的日期信息更新对象的日期,如果文件名称中没有可识别的日期,则不进行任何更新
* 日期提取方法参考 {@link MyDateTimeUtils#pickLocalDate(String)}
*
* @param file 日期来源文件对象
* @param vendorFile 要更新的对象
* @param getter 对象的日期获取方法
* @param setter 对象的日期设置方法
* @param <T> 对象泛型
* @return 是否更新了日期
*/
public static <T> boolean fillApplyDateAbsent(File file, T vendorFile, Function<T, LocalDate> getter,
BiConsumer<T, LocalDate> setter) {
LocalDate applyDate = getter.apply(vendorFile);
if (applyDate != null) {
return false;
}
boolean modified = false;
String fileName = file.getName();
// 从文件的名称中提取日期
LocalDate picked = MyDateTimeUtils.pickLocalDate(fileName);
if (picked != null) {
// 如果提取出的日期不为空则通过setter函数将这个日期设置到vendorFile中并将modified标志设置为true。
setter.accept(vendorFile, picked);
modified = true;
}
return modified;
}
public static boolean isHiddenFile(File file) {
String fileName = file.getName();
if (fileName.equals(FileUtils.FILE_DB_THUMBS)) {
return true;
}
return fileName.startsWith("~$");
}
public static String escapeFileName(String fileName) {
String patternStr = "[\\\\/:*?\"<>|]";
Pattern pattern = Pattern.compile(patternStr);
Matcher matcher = pattern.matcher(fileName);
return matcher.replaceAll("_");
}
/**
* 返回 district 中关于省份的部门zi
*
* @param district 地区
* @return 省份名称
*/
public static String getParentPrefixByDistrict(String district) {
int indexOf = district.indexOf("");
if (indexOf != -1) {
return district.substring(0, indexOf);
}
indexOf = district.indexOf("自治区");
if (indexOf != -1) {
return district.substring(0, 2);
}
indexOf = district.indexOf("");
if (indexOf != -1) {
return district.substring(0, indexOf);
}
return null;
}
public static boolean exists(String path) {
if (!StringUtils.hasText(path)) {
return false;
}
File file = new File(path);
return file.exists();
}
}

View File

@@ -0,0 +1,11 @@
CREATE TABLE supplier_ms.COMPANY_BANK_ACCOUNT
(
ID INT AUTO_INCREMENT NOT NULL,
BANK_ID INT NULL,
OPENING_BANK VARCHAR(255) NULL,
ACCOUNT VARCHAR(255) NULL,
CONSTRAINT pk_company_bank_account PRIMARY KEY (ID)
);
ALTER TABLE supplier_ms.COMPANY_BANK_ACCOUNT
ADD CONSTRAINT FK_COMPANY_BANK_ACCOUNT_ON_BANK FOREIGN KEY (BANK_ID) REFERENCES supplier_ms.BANK (ID);

View File

@@ -0,0 +1,12 @@
package com.ecep.contract.ds.company.repository;
import java.util.Optional;
import com.ecep.contract.ds.MyRepository;
import com.ecep.contract.model.Company;
import com.ecep.contract.model.CompanyBankAccount;
public interface CompanyBankAccountRepository extends MyRepository<CompanyBankAccount, Integer> {
Optional<CompanyBankAccount> findByCompanyAndAccount(Company company, String account);
}

View File

@@ -0,0 +1,16 @@
package com.ecep.contract.ds.company.repository;
import java.util.List;
import org.springframework.stereotype.Repository;
import com.ecep.contract.ds.MyRepository;
import com.ecep.contract.model.Company;
import com.ecep.contract.model.CompanyBlackReason;
@Repository
public interface CompanyBlackReasonRepository extends MyRepository<CompanyBlackReason, Integer> {
List<CompanyBlackReason> findAllByCompany(Company company);
}

View File

@@ -0,0 +1,22 @@
package com.ecep.contract.ds.company.repository;
import java.util.List;
import java.util.Optional;
import org.springframework.stereotype.Repository;
import com.ecep.contract.ds.MyRepository;
import com.ecep.contract.model.Company;
import com.ecep.contract.model.CompanyContact;
@Repository
public interface CompanyContactRepository extends MyRepository<CompanyContact, Integer> {
Optional<CompanyContact> findFirstByCompany(Company company);
List<CompanyContact> findAllByCompany(Company company);
List<CompanyContact> findAllByCompanyAndName(Company company, String name);
int deleteAllByCompany(Company company);
}

View File

@@ -0,0 +1,45 @@
package com.ecep.contract.ds.company.repository;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.stereotype.Repository;
import com.ecep.contract.model.Company;
import com.ecep.contract.model.CompanyContract;
import com.ecep.contract.model.Contract;
@Repository
public interface CompanyContractRepository extends
// JDBC interfaces
CrudRepository<CompanyContract, Integer>, PagingAndSortingRepository<CompanyContract, Integer>,
// JPA interfaces
JpaRepository<CompanyContract, Integer>, JpaSpecificationExecutor<CompanyContract> {
List<CompanyContract> findByCompanyId(int companyId);
List<CompanyContract> findByCompany(Company company);
Stream<CompanyContract> findStreamByCompany(Company company);
Optional<CompanyContract> findByContractId(int contractId);
Optional<CompanyContract> findByContract(Contract contract);
Optional<CompanyContract> findByCompanyAndContract(Company company, Contract contract);
List<CompanyContract> findAllByCompany(Company company);
/**
* Delete all company contracts by company
*
* @param company Company
* @return 删除的记录行数
*/
int deleteAllByCompany(Company company);
}

View File

@@ -0,0 +1,12 @@
package com.ecep.contract.ds.company.repository;
import java.util.List;
import com.ecep.contract.ds.MyRepository;
import com.ecep.contract.model.Company;
import com.ecep.contract.model.CompanyExtendInfo;
public interface CompanyExtendInfoRepository extends MyRepository<CompanyExtendInfo, Integer> {
List<CompanyExtendInfo> findByCompany(Company company);
}

View File

@@ -0,0 +1,15 @@
package com.ecep.contract.ds.company.repository;
import java.util.List;
import com.ecep.contract.CompanyFileType;
import com.ecep.contract.ds.MyRepository;
import com.ecep.contract.model.Company;
import com.ecep.contract.model.CompanyFile;
public interface CompanyFileRepository extends MyRepository<CompanyFile, Integer> {
List<CompanyFile> findByCompany(Company company);
List<CompanyFile> findByCompanyAndType(Company company, CompanyFileType type);
}

View File

@@ -0,0 +1,35 @@
package com.ecep.contract.ds.company.repository;
import org.springframework.stereotype.Repository;
import com.ecep.contract.CompanyFileType;
import com.ecep.contract.ds.other.repository.BaseEnumEntityRepository;
import com.ecep.contract.model.CompanyFileTypeLocal;
@Repository
public interface CompanyFileTypeLocalRepository extends BaseEnumEntityRepository<CompanyFileType, CompanyFileTypeLocal, Integer> {
@Override
default CompanyFileType[] getEnumConstants() {
return CompanyFileType.values();
}
@Override
default CompanyFileTypeLocal newEntity() {
return new CompanyFileTypeLocal();
}
CompanyFileTypeLocal findByTypeAndLang(CompanyFileType type, String lang);
default CompanyFileTypeLocal getCompleteByTypeAndLang(CompanyFileType type, String lang) {
CompanyFileTypeLocal v = findByTypeAndLang(type, lang);
if (v == null) {
v = newEntity();
v.setType(type);
v.setLang(lang);
v.setValue(type.name());
v = save(v);
}
return v;
}
}

View File

@@ -0,0 +1,21 @@
package com.ecep.contract.ds.company.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.stereotype.Repository;
import com.ecep.contract.model.CompanyInvoiceInfo;
/**
* 公司发票信息 Repository
*/
@Repository
public interface CompanyInvoiceInfoRepository extends
// JDBC interfaces
CrudRepository<CompanyInvoiceInfo, Integer>, PagingAndSortingRepository<CompanyInvoiceInfo, Integer>,
// JPA interfaces
JpaRepository<CompanyInvoiceInfo, Integer>, JpaSpecificationExecutor<CompanyInvoiceInfo> {
}

View File

@@ -0,0 +1,36 @@
package com.ecep.contract.ds.company.repository;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import com.ecep.contract.model.CompanyOldName;
@Repository
public interface CompanyOldNameRepository extends
// JDBC interfaces
CrudRepository<CompanyOldName, Integer>, PagingAndSortingRepository<CompanyOldName, Integer>,
// JPA interfaces
JpaRepository<CompanyOldName, Integer>, JpaSpecificationExecutor<CompanyOldName> {
List<CompanyOldName> findAllByCompanyId(Integer companyId);
List<CompanyOldName> findAllByCompanyIdAndName(Integer companyId, String name);
List<CompanyOldName> findAllByName(String name);
List<CompanyOldName> findByNameLike(String searchText);
List<CompanyOldName> findByMemoLike(String searchText);
@Modifying
@Transactional
int deleteAllByCompanyId(Integer companyId);
}

View File

@@ -0,0 +1,36 @@
package com.ecep.contract.ds.company.repository;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.stereotype.Repository;
import com.ecep.contract.model.Company;
@Repository
public interface CompanyRepository extends
// JDBC interfaces
CrudRepository<Company, Integer>, PagingAndSortingRepository<Company, Integer>,
// JPA interfaces
JpaRepository<Company, Integer>, JpaSpecificationExecutor<Company> {
List<Company> findAllByName(String name);
Optional<Company> findFirstByName(String name);
List<Company> findAllByShortName(String shortName);
/**
* @param uniscid 统一社会信用代码
*/
List<Company> findAllByUniscid(String uniscid);
@Query("select u from Company u")
Stream<Company> findAllAsStream();
}

View File

@@ -0,0 +1,14 @@
package com.ecep.contract.ds.company.repository;
import java.util.List;
import com.ecep.contract.ds.MyRepository;
import com.ecep.contract.model.Company;
import com.ecep.contract.model.Invoice;
public interface InvoiceRepository extends MyRepository<Invoice, Integer> {
List<Invoice> findByCompany(Company company);
Invoice findByCode(String invoiceNumber);
}

View File

@@ -0,0 +1,121 @@
package com.ecep.contract.ds.company.service;
import java.util.List;
import java.util.Objects;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import com.ecep.contract.IEntityService;
import com.ecep.contract.MessageHolder;
import com.ecep.contract.ds.company.repository.CompanyBankAccountRepository;
import com.ecep.contract.model.Company;
import com.ecep.contract.model.CompanyBankAccount;
import com.ecep.contract.util.SpecificationUtils;
@Lazy
@Service
@CacheConfig(cacheNames = "company-bank-account")
public class CompanyBankAccountService implements IEntityService<CompanyBankAccount> {
private static final Logger logger = LoggerFactory.getLogger(CompanyBankAccountService.class);
@Lazy
@Autowired
private CompanyBankAccountRepository repository;
public CompanyBankAccount findByAccount(Company company, String account) {
return repository.findByCompanyAndAccount(company, account).orElse(null);
}
public void updateBankAccount(Company company, String bank, String bankAccount, MessageHolder holder) {
boolean modified = false;
if (!StringUtils.hasText(bankAccount)) {
// 空账户不用存储
return;
}
CompanyBankAccount account = findByAccount(company, bankAccount);
if (account == null) {
account = new CompanyBankAccount();
account.setCompany(company);
account.setAccount(bankAccount);
holder.info("新增银行账户" + bankAccount);
modified = true;
}
if (StringUtils.hasText(bank)) {
// 更新开户行
if (!Objects.equals(account.getOpeningBank(), bank)) {
account.setOpeningBank(bank);
holder.info("更新开户行" + bank);
modified = true;
}
}
if (modified) {
save(account);
}
}
public CompanyBankAccount save(CompanyBankAccount account) {
return repository.save(account);
}
public List<CompanyBankAccount> findAll(Specification<CompanyBankAccount> spec, Sort sort) {
return repository.findAll(spec, sort);
}
@Override
public CompanyBankAccount findById(Integer id) {
return repository.findById(id).orElse(null);
}
@Override
public Specification<CompanyBankAccount> getSpecification(String searchText) {
if (!StringUtils.hasText(searchText)) {
return null;
}
return (root, query, builder) -> {
return builder.or(
builder.and(
builder.isNotNull(root.get("bank")),
builder.or(
builder.like(root.get("bank").get("name"), "%" + searchText + "%"),
builder.like(root.get("bank").get("code"), "%" + searchText + "%")
)
),
builder.like(root.get("openingBank"), "%" + searchText + "%"),
builder.like(root.get("account"), "%" + searchText + "%")
);
};
}
@Override
public Page<CompanyBankAccount> findAll(Specification<CompanyBankAccount> spec, Pageable pageable) {
return repository.findAll(spec, pageable);
}
public void delete(CompanyBankAccount entity) {
repository.delete(entity);
}
public List<CompanyBankAccount> searchByCompany(Company company, String searchText) {
Specification<CompanyBankAccount> spec = getSpecification(searchText);
if (company != null) {
spec = SpecificationUtils.and(spec, (root, query, builder) -> {
return builder.equal(root.get("company"), company);
});
}
return repository.findAll(spec, Pageable.ofSize(10)).getContent();
}
}

View File

@@ -0,0 +1,472 @@
package com.ecep.contract.ds.company.service;
import java.io.File;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Consumer;
import com.ecep.contract.util.FileUtils;
import org.hibernate.Hibernate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.util.StringUtils;
import com.ecep.contract.CompanyCustomerFileType;
import com.ecep.contract.CompanyVendorFileType;
import com.ecep.contract.SpringApp;
import com.ecep.contract.ds.company.CompanyFileUtils;
import com.ecep.contract.ds.other.repository.HolidayTableRepository;
import com.ecep.contract.model.Company;
import com.ecep.contract.model.CompanyBasicFile;
import com.ecep.contract.model.CompanyCustomerFile;
import com.ecep.contract.model.CompanyVendorFile;
import com.ecep.contract.model.HolidayTable;
public abstract class CompanyBasicService {
private static final Logger logger = LoggerFactory.getLogger(CompanyBasicService.class);
/**
* 调整日期到工作日
*
* @param date 要调整的日期
* @return 调整的日期
*/
public static LocalDate adjustToWorkDay(LocalDate date) {
if (date.getDayOfWeek() == DayOfWeek.SATURDAY) {
// 再减去1天到周五
date = date.plusDays(-1);
} else if (date.getDayOfWeek() == DayOfWeek.SUNDAY) {
// 再减去2天到周五
date = date.plusDays(-2);
}
HolidayTableRepository holidayTableRepository = SpringApp.getBean(HolidayTableRepository.class);
//TODO 跳过节假日
int tryDays = 15;
while (tryDays-- > 0) {
HolidayTable holidayTable = holidayTableRepository.findById(date).orElse(null);
if (holidayTable == null) {
// 没有节假日定义,检查是否是工作日
DayOfWeek dayOfWeek = date.getDayOfWeek();
if (dayOfWeek == DayOfWeek.SATURDAY) {
date = date.plusDays(-1);
continue;
}
if (dayOfWeek == DayOfWeek.SUNDAY) {
date = date.plusDays(-2);
continue;
}
break;
}
if (!holidayTable.isHoliday()) {
// 不是节假日
break;
}
date = date.plusDays(-1);
}
return date;
}
@Lazy
@Autowired
protected CompanyService companyService;
protected boolean isEditableFile(String fileName) {
return FileUtils.withExtensions(fileName,
FileUtils.XLS, FileUtils.XLSX,
FileUtils.DOC, FileUtils.DOCX);
}
protected boolean isArchiveFile(String fileName) {
return FileUtils.withExtensions(fileName,
FileUtils.PNG, FileUtils.PDF,
FileUtils.JPG, FileUtils.JPEG);
}
public abstract <T, F extends CompanyBasicFile<T>, ID> void deleteFile(F file);
protected <T, F extends CompanyBasicFile<T>, ID> boolean fetchDbFiles(List<F> dbFiles, Map<String, F> map, Consumer<String> status) {
boolean modified = false;
List<File> editFiles = new ArrayList<>();
// 排除掉数据库中重复的
for (F dbFile : dbFiles) {
String filePath = dbFile.getFilePath();
// 没有文件信息,无效记录,删除
if (!StringUtils.hasText(filePath)) {
deleteFile(dbFile);
continue;
}
// 文件不存在或者隐藏文件,删除记录
File file = new File(filePath);
if (!file.exists() || CompanyFileUtils.isHiddenFile(file)) {
deleteFile(dbFile);
continue;
}
// old 是冲突的按dbFiles顺序旧的list前面的
F old = map.put(filePath, dbFile);
// 目录有重复删除
if (old != null) {
deleteFile(old);
}
String editFilePath = dbFile.getEditFilePath();
if (!Objects.equals(filePath, editFilePath)) {
// 没有文件信息,无效记录,删除
if (StringUtils.hasText(editFilePath)) {
File editFile = new File(editFilePath);
if (editFile.exists()) {
editFiles.add(editFile);
} else {
dbFile.setEditFilePath("");
}
}
}
// 类型未设置,补充类型
if (dbFile.getType() == null) {
if (fillFileAsDefaultType(dbFile, file, status)) {
modified = true;
}
}
}
for (File editFile : editFiles) {
String editFilePath = editFile.getAbsolutePath();
F dup = map.remove(editFilePath);
// 目录有重复删除
if (dup != null) {
deleteFile(dup);
}
}
return modified;
}
/**
* dbFile 的 Type 未设置时,设置为默认类型
*
* @param dbFile 要设置的 对象
* @param file 相关文件对象
* @param status 状态输出
* @param <T> 类型类
* @param <F> 文件类
* @return 是否修改了
* @see CompanyVendorFile
* @see CompanyVendorFileType
* @see CompanyCustomerFile
* @see CompanyCustomerFileType
*/
protected abstract <T, F extends CompanyBasicFile<T>> boolean fillFileAsDefaultType(F dbFile, File file, Consumer<String> status);
protected void moveFileToCompany(Company company, List<File> needMoveToCompanyPath) {
if (needMoveToCompanyPath.isEmpty()) {
return;
}
if (!Hibernate.isInitialized(company)) {
company = companyService.findById(company.getId());
}
String companyPath = company.getPath();
if (!StringUtils.hasText(companyPath)) {
return;
}
for (File file : needMoveToCompanyPath) {
File dest = new File(companyPath, file.getName());
if (file.renameTo(dest)) {
//
if (logger.isInfoEnabled()) {
logger.info("{} -> {}", file.getAbsolutePath(), dest.getAbsolutePath());
}
} else {
//
if (dest.exists()) {
if (file.delete()) {
if (logger.isInfoEnabled()) {
logger.info("Delete File {}", file.getAbsolutePath());
}
}
}
}
}
// 公司目录下文件更新后,待公司文件自行处理
}
/**
* 遍历扫描 path 目录下的文件,
*
* @param path
* @param needMoveToCompanyPath
* @param retrieveFiles
* @param map
* @param status
* @param <T>
* @param <F>
*/
protected <T, F extends CompanyBasicFile<T>> void fetchFiles(
String path,
List<File> needMoveToCompanyPath,
List<F> retrieveFiles,
Map<String, F> map,
Consumer<String> status
) {
if (!StringUtils.hasText(path)) {
return;
}
File dir = new File(path);
if (!dir.exists()) {
return;
}
File[] files = dir.listFiles();
if (files == null) {
return;
}
List<File> step1 = new ArrayList<>();
for (File file : files) {
// 只处理文件
if (!file.isFile() || CompanyFileUtils.isHiddenFile(file)) {
continue;
}
if (CompanyFileUtils.isCompanyFile(file)) {
needMoveToCompanyPath.add(file);
continue;
}
// 先把所有文件加到列表中
step1.add(file);
}
if (!step1.isEmpty()) {
// 第一步,处理已经存在的
for (File file : new ArrayList<>(step1)) {
String filePath = file.getAbsolutePath();
if (map.containsKey(filePath)) {
// 已记录
F customerFile = map.get(filePath);
if (fillFile(customerFile, file, step1, status)) {
retrieveFiles.add(customerFile);
}
step1.remove(file);
}
}
// 第二步骤,再处理
while (!step1.isEmpty()) {
File file = step1.removeLast();
F filled = fillFileType(file, step1, status);
if (filled != null) {
retrieveFiles.add(filled);
}
}
}
}
/**
* 填充文件类型
*
* @param file
* @param fileList
* @param status 状态输出
* @param <T> 类型类
* @param <F> 文件类
*/
protected abstract <T, F extends CompanyBasicFile<T>> F fillFileType(File file, List<File> fileList, Consumer<String> status);
/**
* @param customerFile 文件对象
* @param file 相关文件
* @param fileList 待处理文件列表
* @param status 状态输出
* @param <T> 类型类
* @param <F> 文件类
* @return true 有修改
*/
protected <T, F extends CompanyBasicFile<T>> boolean fillFile(F customerFile, File file, List<File> fileList, Consumer<String> status) {
String fileName = file.getName();
boolean modified = CompanyFileUtils.fillApplyDateAbsent(file, customerFile, F::getSignDate, F::setSignDate);
// 评估表
if (isEvaluationFile(fileName)) {
if (fillFileAsEvaluationFile(customerFile, file, fileList, status)) {
modified = true;
}
} else {
if (!Objects.equals(file.getAbsolutePath(), customerFile.getFilePath())) {
customerFile.setFilePath(file.getAbsolutePath());
modified = true;
}
}
return modified;
}
/**
* 以评价表单模板。填充文件信息
*
* @param customerFile 文件对象
* @param file 相关文件
* @param fileList 待处理文件列表
* @param status 状态输出
* @param <T> 类型类
* @param <F> 文件类
* @return true文件对象有修改否则返回false
*/
protected <T, F extends CompanyBasicFile<T>> boolean fillFileAsEvaluationFile(F customerFile, File file, List<File> fileList, Consumer<String> status) {
boolean modified = setFileTypeAsEvaluationForm(customerFile);
String fileName = file.getName();
// 文件全路径
String fileAbsolutePath = file.getAbsolutePath();
if (isEditableFile(fileName)) {
// 是可编辑文件时
if (!Objects.equals(fileAbsolutePath, customerFile.getEditFilePath())) {
customerFile.setEditFilePath(fileAbsolutePath);
modified = true;
}
if (useAsEditableFile(customerFile, file, fileList, status)) {
modified = true;
}
} else if (isArchiveFile(fileName)) {
// 存档文件时
if (!Objects.equals(fileAbsolutePath, customerFile.getFilePath())) {
customerFile.setFilePath(fileAbsolutePath);
modified = true;
}
if (useAsArchiveFile(customerFile, file, fileList, status)) {
modified = true;
}
} else {
customerFile.setFilePath(file.getAbsolutePath());
}
return modified;
}
private <T, F extends CompanyBasicFile<T>> boolean useAsEditableFile(F customerFile, File file, List<File> fileList, Consumer<String> status) {
if (fileList == null) {
return false;
}
// 检查存档文件
if (StringUtils.hasText(customerFile.getFilePath())) {
// 移除 存档文件
File archiveFile = new File(customerFile.getFilePath());
fileList.remove(archiveFile);
return false;
}
// 未关联存档文件,去找 fileList 查
if (fileList.isEmpty()) {
// 文件全路径
String fileAbsolutePath = file.getAbsolutePath();
// 当没有其他文件时,与 EditFile 相同
if (!Objects.equals(fileAbsolutePath, customerFile.getFilePath())) {
customerFile.setFilePath(fileAbsolutePath);
return true;
}
return false;
}
File archiveFile = null;
// 文件名
String fileName = file.getName();
// 文件名,不含后缀
String name = StringUtils.stripFilenameExtension(fileName);
for (File f : fileList) {
// 查找存档文件
if (f.getName().startsWith(name) && isArchiveFile(f.getName())) {
archiveFile = f;
break;
}
}
// 没有匹配到文件
if (archiveFile == null) {
return false;
}
if (fileList.remove(archiveFile)) {
customerFile.setFilePath(archiveFile.getAbsolutePath());
return true;
}
return false;
}
private <T, F extends CompanyBasicFile<T>> boolean useAsArchiveFile(F customerFile, File file, List<File> fileList, Consumer<String> status) {
if (fileList == null) {
return false;
}
// 未关联存档文件,去找 fileList 查
if (fileList.isEmpty()) {
return false;
}
// 检查可编辑文件
if (StringUtils.hasText(customerFile.getEditFilePath())) {
// 移除 可编辑文件
File editFile = new File(customerFile.getEditFilePath());
fileList.remove(editFile);
return false;
}
File editFile = null;
// 文件名
String fileName = file.getName();
// 文件名,不含后缀
String name = StringUtils.stripFilenameExtension(fileName);
for (File f : fileList) {
// 查找存档文件
if (f.getName().startsWith(name) && isEditableFile(f.getName())) {
editFile = f;
break;
}
}
// 没有匹配到文件
if (editFile == null) {
return false;
}
if (fileList.remove(editFile)) {
String editFilePath = editFile.getAbsolutePath();
if (!Objects.equals(editFilePath, customerFile.getEditFilePath())) {
customerFile.setEditFilePath(editFilePath);
return true;
}
}
return false;
}
/**
* 设置文件类型为表单文件
*
* @param file 文件对象
* @param <T> 类型类
* @param <F> 文件类
* @return true 文件对象有修改否则false
*/
protected abstract <T, F extends CompanyBasicFile<T>> boolean setFileTypeAsEvaluationForm(F file);
/**
* 判定 参数 fileName 是否是一个评价表文件
*
* @param fileName 文件名称
* @return true 是评价表否则false
*/
protected abstract boolean isEvaluationFile(String fileName);
}

View File

@@ -0,0 +1,68 @@
package com.ecep.contract.ds.company.service;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import com.ecep.contract.IEntityService;
import com.ecep.contract.ds.company.repository.CompanyBlackReasonRepository;
import com.ecep.contract.model.Company;
import com.ecep.contract.model.CompanyBlackReason;
@Lazy
@Service
public class CompanyBlackReasonService implements IEntityService<CompanyBlackReason> {
private static final Logger logger = LoggerFactory.getLogger(CompanyContactService.class);
@Autowired
private CompanyBlackReasonRepository repository;
public CompanyBlackReason findById(Integer id) {
return repository.findById(id).orElse(null);
}
@Override
public Specification<CompanyBlackReason> getSpecification(String searchText) {
if (!StringUtils.hasText(searchText)) {
return null;
}
return (root, query, builder) -> {
return builder.or(
builder.like(root.get("applyName"), "%" + searchText + "%"),
builder.like(root.get("blackReason"), "%" + searchText + "%"),
builder.like(root.get("description"), "%" + searchText + "%")
);
};
}
@Override
public Page<CompanyBlackReason> findAll(Specification<CompanyBlackReason> spec, Pageable pageable) {
return repository.findAll(spec, pageable);
}
public void delete(CompanyBlackReason entity) {
repository.delete(entity);
}
public List<CompanyBlackReason> findAll(Specification<CompanyBlackReason> spec, Sort by) {
return repository.findAll(spec, by);
}
public List<CompanyBlackReason> findAllByCompany(Company company) {
return repository.findAllByCompany(company);
}
public CompanyBlackReason save(CompanyBlackReason companyBlackReason) {
return repository.save(companyBlackReason);
}
}

View File

@@ -0,0 +1,109 @@
package com.ecep.contract.ds.company.service;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import com.ecep.contract.IEntityService;
import com.ecep.contract.ds.company.repository.CompanyContactRepository;
import com.ecep.contract.model.Company;
import com.ecep.contract.model.CompanyContact;
import com.ecep.contract.util.MyStringUtils;
import com.ecep.contract.util.SpecificationUtils;
/**
* 公司联系人服务
*/
@Lazy
@Service
@CacheConfig(cacheNames = "company-contact")
public class CompanyContactService implements IEntityService<CompanyContact> {
private static final Logger logger = LoggerFactory.getLogger(CompanyContactService.class);
@Autowired
private CompanyContactRepository companyContactRepository;
public CompanyContact save(CompanyContact contact) {
return companyContactRepository.save(contact);
}
public void resetTo(Company from, Company to) {
// 曾用名 关联到 updater
List<CompanyContact> list = companyContactRepository.findAllByCompany(from);
if (list.isEmpty()) {
return;
}
for (CompanyContact oldName : list) {
oldName.setMemo(MyStringUtils.appendIfAbsent(oldName.getMemo(), "转自 " + from.getId()));
oldName.setCompany(to);
}
companyContactRepository.saveAll(list);
}
public void deleteByCompany(Company company) {
int deleted = companyContactRepository.deleteAllByCompany(company);
if (deleted > 0) {
if (logger.isInfoEnabled()) {
logger.info("Delete {} records by company:#{}", deleted, company.getId());
}
}
}
public void delete(CompanyContact entity) {
companyContactRepository.delete(entity);
}
public CompanyContact findFirstByCompany(Company company) {
return companyContactRepository.findFirstByCompany(company).orElse(null);
}
public CompanyContact findById(Integer id) {
return companyContactRepository.findById(id).orElse(null);
}
@Override
public Specification<CompanyContact> getSpecification(String searchText) {
if (!StringUtils.hasText(searchText)) {
return null;
}
return (root, query, builder) -> {
return builder.or(
builder.like(root.get("name"), "%" + searchText + "%"),
builder.like(root.get("phone"), "%" + searchText + "%"),
builder.like(root.get("email"), "%" + searchText + "%"),
builder.like(root.get("position"), "%" + searchText + "%"),
builder.like(root.get("memo"), "%" + searchText + "%")
);
};
}
@Override
public Page<CompanyContact> findAll(Specification<CompanyContact> spec, Pageable pageable) {
return companyContactRepository.findAll(spec, pageable);
}
public List<CompanyContact> searchByCompany(Company company, String userText) {
Specification<CompanyContact> spec = SpecificationUtils.and((root, query, builder) -> {
return builder.equal(root.get("company"), company);
}, getSpecification(userText));
return companyContactRepository.findAll(spec);
}
public List<CompanyContact> findAll(Specification<CompanyContact> spec, Sort sort) {
return companyContactRepository.findAll(spec, sort);
}
public List<CompanyContact> findAllByCompanyAndName(Company company, String contactName) {
return companyContactRepository.findAllByCompanyAndName(company, contactName);
}
}

View File

@@ -0,0 +1,75 @@
package com.ecep.contract.ds.company.service;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import com.ecep.contract.ds.company.repository.CompanyExtendInfoRepository;
import com.ecep.contract.model.Company;
import com.ecep.contract.model.CompanyExtendInfo;
/**
* 公司文件服务
*/
@Lazy
@Service
@CacheConfig(cacheNames = "company-extend-info")
public class CompanyExtendInfoService {
private static final Logger logger = LoggerFactory.getLogger(CompanyExtendInfoService.class);
@Autowired
private CompanyExtendInfoRepository repository;
@Cacheable(key = "#p0")
public CompanyExtendInfo findById(int id) {
return repository.findById(id).orElse(null);
}
public List<CompanyExtendInfo> findAll(Specification<CompanyExtendInfo> spec, Sort sort) {
return repository.findAll(spec, sort);
}
@Caching(
evict = {
@CacheEvict(key = "#p0.id"),
@CacheEvict(key = "'byCompany-'+#p0.company.id")
}
)
public void delete(CompanyExtendInfo extendInfo) {
repository.delete(extendInfo);
}
@Caching(
evict = {
@CacheEvict(key = "#p0.id"),
@CacheEvict(key = "'byCompany-'+#p0.company.id")
}
)
public CompanyExtendInfo save(CompanyExtendInfo extendInfo) {
return repository.save(extendInfo);
}
@Cacheable(key = "'byCompany-'+#p0")
public CompanyExtendInfo findByCompany(Company company) {
List<CompanyExtendInfo> list = repository.findByCompany(company);
if (list.isEmpty()) {
CompanyExtendInfo extendInfo = new CompanyExtendInfo();
extendInfo.setCompany(company);
extendInfo.setDisableVerify(false);
return repository.save(extendInfo);
}
return list.getFirst();
}
}

View File

@@ -0,0 +1,635 @@
package com.ecep.contract.ds.company.service;
import java.io.File;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import com.ecep.contract.CompanyFileType;
import com.ecep.contract.IEntityService;
import com.ecep.contract.MyDateTimeUtils;
import com.ecep.contract.SpringApp;
import com.ecep.contract.cloud.rk.CloudRkService;
import com.ecep.contract.cloud.tyc.CloudTycService;
import com.ecep.contract.constant.CloudServiceConstant;
import com.ecep.contract.ds.company.CompanyFileUtils;
import com.ecep.contract.ds.company.repository.CompanyFileRepository;
import com.ecep.contract.ds.company.repository.CompanyFileTypeLocalRepository;
import com.ecep.contract.ds.company.repository.CompanyOldNameRepository;
import com.ecep.contract.ds.contract.service.ContractService;
import com.ecep.contract.model.Company;
import com.ecep.contract.model.CompanyFile;
import com.ecep.contract.model.CompanyFileTypeLocal;
import com.ecep.contract.model.CompanyOldName;
import com.ecep.contract.model.Contract;
/**
* 公司文件服务
*/
@Lazy
@Service
@CacheConfig(cacheNames = "company-file")
public class CompanyFileService implements IEntityService<CompanyFile> {
public final static String ENTERPRISE_REPORT = "企业信用报告";
public final static String BUSINESS_LICENSE = "营业执照";
public final static String ORGANIZATION_CODE_CERTIFICATE = "组织机构代码证";
public final static String OPERATION_CERTIFICATE = "操作证";
public final static String PERMIT_CERTIFICATE = "许可证";
public final static String REGISTRATION_CERTIFICATE = "登记证";
private static final Logger logger = LoggerFactory.getLogger(CompanyFileService.class);
@Lazy
@Autowired
private CompanyFileRepository companyFileRepository;
@Lazy
@Autowired
private CompanyOldNameRepository companyOldNameRepository;
@Lazy
@Autowired
private CompanyFileTypeLocalRepository fileTypeLocalRepository;
@Cacheable(key = "#p0")
public CompanyFile findById(Integer id) {
return companyFileRepository.findById(id).orElse(null);
}
@Override
public Page<CompanyFile> findAll(Specification<CompanyFile> spec, Pageable pageable) {
return companyFileRepository.findAll(spec, pageable);
}
public List<CompanyFile> findFileByCompanyAndType(Company company, CompanyFileType type) {
return companyFileRepository.findByCompanyAndType(company, type);
}
@Override
public Specification<CompanyFile> getSpecification(String searchText) {
if (!StringUtils.hasText(searchText)) {
return null;
}
return (root, query, builder) -> {
return builder.or(builder.like(root.get("filePath"), "%" + searchText + "%"));
};
}
@Cacheable(key = "'type-locals-'+#p0")
public Map<CompanyFileType, CompanyFileTypeLocal> findAllFileTypes(String lang) {
return fileTypeLocalRepository.getCompleteMapByLocal(lang);
}
// public List<CompanyFileTypeLocal> findAllFileTypes(String lang) {
// Map<CompanyFileType, CompanyFileTypeLocal> map =
// fileTypeLocalRepository.getCompleteMapByLocal(lang);
// List<CompanyFileTypeLocal> list = new ArrayList<>(map.values());
// list.sort((o1, o2) -> Objects.compare(o1.getValue(), o2.getValue(),
// String::compareTo));
// return list;
// }
/**
* 根据公司的合同的资信报告文件,推算下一个咨询报告日期
*
* @param company 公司
* @param state 状态输出
* @return 下一个咨询报告日期
*/
public LocalDate getNextCreditReportDate(Company company, Consumer<String> state) {
// 检索全部合同
ContractService contractService = SpringApp.getBean(ContractService.class);
List<Contract> contractList = contractService.findAllByCompany(company);
if (contractList.isEmpty()) {
state.accept("未发现已登记的合同");
return null;
}
LocalDate minDate = LocalDate.of(2023, 1, 1);
List<Contract> contracts = contractList.stream()
.filter(v -> !v.getSetupDate().isBefore(minDate))
.sorted(Comparator.comparing(Contract::getSetupDate))
.toList();
if (contracts.isEmpty()) {
state.accept("没有发现待处理的合同");
return null;
}
// 检索资信报告
List<CompanyFile> files = findFileByCompanyAndType(company, CompanyFileType.CreditReport);
if (files.isEmpty()) {
Contract first = contracts.getFirst();
// 没有资信报告,返回第一个合同的提交日期
state.accept("没有资信报告,推荐使用第一个合同 " + first.getCode() + " 的日期 " + first.getSetupDate());
return first.getSetupDate();
}
for (Contract contract : contracts) {
if (files.stream().noneMatch(v -> MyDateTimeUtils.dateValidFilter(contract.getSetupDate(), v.getApplyDate(),
v.getExpiringDate(), 1))) {
state.accept("发现未匹配的合同 " + contract.getCode() + " " + contract.getSetupDate());
return contract.getSetupDate();
}
}
return null;
}
/**
* 验证企业文件
* <p>
* 检查是否有类型为{@link CompanyFileType#CreditReport
* 资讯评估}的文件且参数verifyDate在文件的{@link CompanyFile#getApplyDate()}和{@link CompanyFile#getExpiringDate()}
* ()}指定验证日期内有
* <p>
* 2023-01-01后要求有资信评估报告
*
* @param company 检查的公司对象
* @param verifyDate 检查日期
* @param status 状态输出
* @see CompanyFile
* @see CompanyFileType
*/
public void verify(Company company, LocalDate verifyDate, Consumer<String> status) {
if (verifyDate.isBefore(LocalDate.of(2023, 1, 1))) {
// 不检查2023-01-01之前的资信评估报告
return;
}
// 查询公司的资信评估报告
List<CompanyFile> files = findFileByCompanyAndType(company, CompanyFileType.CreditReport);
CompanyFile companyFile = files.stream()
.filter(v -> v.getApplyDate() != null && v.getExpiringDate() != null)
.filter(v -> MyDateTimeUtils.dateValidFilter(verifyDate, v.getApplyDate(), v.getExpiringDate(), 30))
.findFirst().orElse(null);
if (companyFile == null) {
List<LocalDate> dates = new ArrayList<>();
files.stream()
.filter(v -> v.getApplyDate() != null && !verifyDate.isBefore(v.getApplyDate()))
.max(Comparator.comparing(CompanyFile::getApplyDate))
.map(CompanyFile::getApplyDate)
.ifPresent(dates::add);
files.stream()
.filter(v -> v.getExpiringDate() != null && !verifyDate.isAfter(v.getExpiringDate()))
.min(Comparator.comparing(CompanyFile::getApplyDate))
.map(CompanyFile::getApplyDate)
.ifPresent(dates::add);
if (dates.isEmpty()) {
status.accept("未匹配到资信评估报告");
} else if (dates.size() == 1) {
status.accept("未匹配到资信评估报告, 最接近日期:" + dates.getFirst());
} else {
LocalDate localDate = dates.stream().max(LocalDate::compareTo).orElse(null);
status.accept("未匹配到资信评估报告, 最接近日期:" + localDate);
}
}
}
/**
* 保存企业文件
*
* @param companyFile 企业文件
* @return 保存后的企业文件
*/
public CompanyFile save(CompanyFile companyFile) {
return companyFileRepository.save(companyFile);
}
public List<CompanyFile> findAll(Specification<CompanyFile> spec, Sort sort) {
return companyFileRepository.findAll(spec, sort);
}
public void deleteById(int id) {
companyFileRepository.deleteById(id);
}
public void delete(CompanyFile file) {
companyFileRepository.delete(file);
}
public List<CompanyFile> findByCompany(Company company) {
return companyFileRepository.findByCompany(company);
}
/**
* 重置 公司文件
*
* @param company 要重置的公司对象
* @param status 输出
*/
public boolean reBuildingFiles(Company company, Consumer<String> status) {
List<CompanyFile> dbFiles = companyFileRepository.findByCompany(company);
List<CompanyFile> retrieveFiles = new ArrayList<>();
boolean modfied = false;
Map<String, CompanyFile> map = new HashMap<>();
// 排除掉数据库中重复的
for (CompanyFile dbFile : dbFiles) {
String filePath = dbFile.getFilePath();
// 没有文件信息,无效记录,删除
if (!StringUtils.hasText(filePath)) {
companyFileRepository.delete(dbFile);
modfied = true;
continue;
}
// 目录不存在,删除
File dir = new File(filePath);
if (!dir.exists()) {
companyFileRepository.delete(dbFile);
modfied = true;
continue;
}
CompanyFile old = map.put(filePath, dbFile);
// 目录有重复删除
if (old != null) {
companyFileRepository.delete(old);
modfied = true;
}
}
Map<String, File> directoryMap = new HashMap<>();
// 公司目录
if (StringUtils.hasText(company.getPath())) {
File dir = new File(company.getPath());
directoryMap.put(company.getName(), dir);
}
// 获取所有曾用名
for (CompanyOldName companyOldName : companyOldNameRepository.findAllByCompanyId(company.getId())) {
String path = companyOldName.getPath();
if (StringUtils.hasText(path)) {
File dir = new File(path);
directoryMap.put(companyOldName.getName(), dir);
}
}
for (Map.Entry<String, File> entry : directoryMap.entrySet()) {
String companyName = entry.getKey();
File dir = entry.getValue();
if (!StringUtils.hasText(companyName)) {
continue;
}
if (dir == null || !dir.exists()) {
continue;
}
File[] files = dir.listFiles();
if (files == null) {
// 文件系统出错或者没有相关文件
continue;
}
for (File file : files) {
// 只处理文件
if (!file.isFile() || CompanyFileUtils.isHiddenFile(file)) {
continue;
}
String filePath = file.getAbsolutePath();
if (!map.containsKey(filePath)) {
// 未记录
CompanyFile filled = fillFileType(file, status);
retrieveFiles.add(filled);
}
}
}
status.accept("导入 " + retrieveFiles.size() + " 个文件");
if (retrieveFiles.isEmpty()) {
return modfied;
}
// update db
retrieveFiles.forEach(v -> v.setCompany(company));
companyFileRepository.saveAll(retrieveFiles);
return true;
}
/**
* 从文件名生成公司文件对象,文件已经存在公司对应的存储目录下
*
* @param file 文件
* @param status 状态输出
* @return 公司文件对象
*/
private CompanyFile fillFileType(File file, Consumer<String> status) {
String fileName = file.getName();
CompanyFile companyFile = new CompanyFile();
companyFile.setType(CompanyFileType.General);
companyFile.setFilePath(file.getAbsolutePath());
fillApplyDateAndExpiringDateAbsent(file, companyFile);
// 天眼查 基础版企业信用报告
if (fileName.contains(CloudTycService.TYC_ENTERPRISE_BASIC_REPORT)
|| fileName.contains(CloudTycService.TYC_ENTERPRISE_MAJOR_REPORT)
|| fileName.contains(CloudTycService.TYC_ENTERPRISE_ANALYSIS_REPORT)) {
companyFile.setType(CompanyFileType.CreditReport);
fillExpiringDateAbsent(companyFile);
return companyFile;
}
// 天眼查 企业信用信息公示报告
if (fileName.contains(CloudTycService.TYC_ENTERPRISE_CREDIT_REPORT)) {
companyFile.setType(CompanyFileType.CreditInfoPublicityReport);
return companyFile;
}
// 集团相关方平台 元素征信 企业征信报告
if (fileName.contains(CloudServiceConstant.RK_VENDOR_NAME)
&& fileName.contains(CloudRkService.ENTERPRISE_CREDIT_REPORT)) {
companyFile.setType(CompanyFileType.CreditReport);
fillExpiringDateAbsent(companyFile);
return companyFile;
}
// 营业执照
if (fileName.contains(BUSINESS_LICENSE)) {
companyFile.setType(CompanyFileType.BusinessLicense);
return companyFile;
}
// 其他企业信用报告
if (fileName.contains(ENTERPRISE_REPORT)) {
companyFile.setType(CompanyFileType.CreditReport);
fillExpiringDateAbsent(companyFile);
return companyFile;
}
return companyFile;
}
/**
* 补齐有效期
*/
private void fillExpiringDateAbsent(CompanyFile file) {
LocalDate expiringDate = file.getExpiringDate();
if (expiringDate == null) {
LocalDate applyDate = file.getApplyDate();
if (applyDate != null) {
expiringDate = applyDate.plusYears(1);
file.setExpiringDate(expiringDate);
}
}
}
private static void fillApplyDateAndExpiringDateAbsent(File file, CompanyFile companyFile) {
LocalDate applyDate = companyFile.getApplyDate();
if (applyDate != null) {
return;
}
String fileName = file.getName();
Pattern pattern = Pattern.compile(MyDateTimeUtils.REGEX_DATE);
Matcher matcher = pattern.matcher(fileName);
while (matcher.find()) {
// 找到第一个日期,记作起始日期
String date = matcher.group();
try {
LocalDate n = LocalDate.parse(date);
companyFile.setApplyDate(n);
// 如果 截至日期未设置,则第二个日期记作截至日期(如有)
LocalDate expiringDate = companyFile.getExpiringDate();
if (expiringDate == null) {
while (matcher.find()) {
date = matcher.group();
try {
n = LocalDate.parse(date);
companyFile.setExpiringDate(n);
break;
} catch (Exception e) {
if (logger.isDebugEnabled()) {
logger.debug(
"parse date failure, it used to set ExpiringDate, {} from {} by Regex:{}, @{}",
date, fileName, MyDateTimeUtils.REGEX_DATE, companyFile);
}
}
}
}
break;
} catch (Exception e) {
if (logger.isDebugEnabled()) {
logger.debug("parse date failure, it used to set ApplyDate, {} from {} by Regex:{}, @{}",
date, fileName, MyDateTimeUtils.REGEX_DATE, companyFile);
}
}
}
}
/**
* 移动文件到企业目录下
*
* @param company 企业对象
* @param files 要被移动的文件集合,需要从中选择需要的
* @param status 状态输出
*/
public boolean retrieveFromDownloadFiles(Company company, File[] files, Consumer<String> status) {
Map<String, File> map = new HashMap<>();
File home = new File(company.getPath());
map.put(company.getName(), home);
List<CompanyFile> retrieveFiles = new ArrayList<>();
// 获取所有曾用名
for (CompanyOldName companyOldName : companyOldNameRepository.findAllByCompanyId(company.getId())) {
String name = companyOldName.getName();
if (!StringUtils.hasText(name)) {
continue;
}
File dir = null;
String path = companyOldName.getPath();
if (StringUtils.hasText(path)) {
dir = new File(path);
}
map.put(name, dir);
}
// 对所有文件进行遍历
for (int i = 0; i < files.length; i++) {
File file = files[i];
// 只处理文件
if (!file.isFile()) {
continue;
}
String prefix = (i + 1) + "/" + files.length + ":";
Consumer<String> inner = (str) -> {
status.accept(prefix + str);
};
String fileName = file.getName();
inner.accept(fileName);
for (Map.Entry<String, File> entry : map.entrySet()) {
String companyName = entry.getKey();
// 必须要包含公司名称否则无法区分
if (!fileName.contains(companyName)) {
continue;
}
// 文件存储的目的地目录
File dir = entry.getValue();
if (dir == null) {
dir = home;
}
CompanyFile filled = fillDownloadFileType(company, file, companyName, dir, inner);
if (filled != null) {
retrieveFiles.add(filled);
}
}
}
status.accept("导入 " + retrieveFiles.size() + " 个文件");
if (retrieveFiles.isEmpty()) {
return false;
}
// update db
retrieveFiles.forEach(v -> v.setCompany(company));
companyFileRepository.saveAll(retrieveFiles);
return true;
}
/**
* 从文件名生成公司文件对象
* 文件从下载目录中导入
*
* @param company 公司对象
* @param file 导入的文件对象
* @param companyName 公司名称
* @param destDir 目标目录
* @param status 状态输出
* @return 生成的公司文件对象如果无法转换则返回null
*/
private CompanyFile fillDownloadFileType(Company company, File file, String companyName, File destDir,
Consumer<String> status) {
String fileName = file.getName();
// 天眼查的报告
// 目前只有 基础版企业信用报告, 企业信用信息公示报告下载保存时的文件名中没有天眼查
if (CloudTycService.isTycReport(fileName)) {
CompanyFile companyFile = new CompanyFile();
companyFile.setType(CompanyFileType.CreditReport);
fillApplyDateAbsent(file, companyFile);
String destFileName = fileName;
// 重命名 基础版企业信用报告
for (String report : Arrays.asList(
CloudTycService.TYC_ENTERPRISE_ANALYSIS_REPORT,
CloudTycService.TYC_ENTERPRISE_BASIC_REPORT,
CloudTycService.TYC_ENTERPRISE_MAJOR_REPORT)) {
if (fileName.contains(report)) {
LocalDate applyDate = companyFile.getApplyDate();
if (applyDate == null) {
applyDate = LocalDate.now();
companyFile.setApplyDate(applyDate);
}
String formatted = MyDateTimeUtils.format(applyDate);
String extension = StringUtils.getFilenameExtension(fileName);
destFileName = String.format("%s_%s_%s_%s.%s",
companyName, CloudServiceConstant.TYC_NAME, report, formatted, extension);
}
}
// 重新设置 企业分析报告 未普通文件
// if (fileName.contains(CloudTycService.TYC_ENTERPRISE_ANALYSIS_REPORT)) {
// companyFile.setType(General);
// }
File dest = new File(destDir, destFileName);
// 移动文件
if (!file.renameTo(dest)) {
// 移动失败时
status.accept(fileName + " 无法移动到 " + dest.getAbsolutePath());
return null;
}
status.accept(fileName + " 移动到 " + dest.getAbsolutePath());
companyFile.setFilePath(dest.getAbsolutePath());
//
if (companyFile.getExpiringDate() == null) {
if (companyFile.getApplyDate() != null) {
companyFile.setExpiringDate(companyFile.getApplyDate().plusYears(1));
}
}
return companyFile;
}
// 企业信用信息公示报告
if (fileName.contains(CloudTycService.TYC_ENTERPRISE_CREDIT_REPORT)) {
CompanyFile companyFile = new CompanyFile();
companyFile.setType(CompanyFileType.CreditInfoPublicityReport);
fillApplyDateAbsent(file, companyFile);
File dest = new File(destDir, fileName);
// 移动文件
if (!file.renameTo(dest)) {
if (dest.exists()) {
// 尝试删除已经存在的文件
if (!dest.delete()) {
status.accept("覆盖时,无法删除已存在的文件 " + dest.getAbsolutePath());
return null;
}
if (file.renameTo(dest)) {
Optional<CompanyFile> one = companyFileRepository.findOne(((root, query, builder) -> {
return builder.and(
builder.equal(root.get("filePath"), dest.getAbsolutePath()),
builder.equal(root.get("company"), company));
}));
if (one.isPresent()) {
companyFile = one.get();
}
} else {
status.accept(fileName + " 无法覆盖到 " + dest.getAbsolutePath());
return null;
}
} else {
status.accept(fileName + " 无法移动到 " + dest.getAbsolutePath());
return null;
}
}
status.accept(fileName + " 移动到 " + dest.getAbsolutePath());
companyFile.setFilePath(dest.getAbsolutePath());
return companyFile;
}
return null;
}
/**
* 当 ApplyDate 未设置时,尝试使用文件名中包含的日期
*/
private static void fillApplyDateAbsent(File file, CompanyFile companyFile) {
LocalDate applyDate = companyFile.getApplyDate();
if (applyDate != null) {
return;
}
String fileName = file.getName();
// 从文件名中提取日期
LocalDate picked = MyDateTimeUtils.pickLocalDate(fileName);
if (picked != null) {
companyFile.setApplyDate(picked);
}
}
}

View File

@@ -0,0 +1,53 @@
package com.ecep.contract.ds.company.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import com.ecep.contract.ds.company.repository.CompanyInvoiceInfoRepository;
import com.ecep.contract.model.Company;
import com.ecep.contract.model.CompanyInvoiceInfo;
/**
* 公司发票信息服务
*/
@Lazy
@Service
@CacheConfig(cacheNames = "company-invoice-info")
public class CompanyInvoiceInfoService {
@Lazy
@Autowired
private CompanyInvoiceInfoRepository repository;
@Cacheable(key = "#p0")
public CompanyInvoiceInfo findById(int id) {
return repository.findById(id).orElse(null);
}
public List<CompanyInvoiceInfo> searchByCompany(Company company, String searchText) {
Specification<CompanyInvoiceInfo> spec = (root, query, builder) -> {
return builder.or(
builder.like(root.get("name"), "%" + searchText + "%"),
builder.like(root.get("taxId"), "%" + searchText + "%"),
builder.like(root.get("address"), "%" + searchText + "%"),
builder.like(root.get("phone"), "%" + searchText + "%"),
builder.like(root.get("bankName"), "%" + searchText + "%"),
builder.like(root.get("bankAccount"), "%" + searchText + "%")
);
};
if (company != null) {
spec = spec.and((root, query, builder) -> {
return builder.equal(root.get("company"), company);
});
}
return repository.findAll(spec, Pageable.ofSize(10)).getContent();
}
}

View File

@@ -0,0 +1,208 @@
package com.ecep.contract.ds.company.service;
import java.io.File;
import java.time.LocalDate;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import com.ecep.contract.IEntityService;
import com.ecep.contract.ds.company.CompanyFileUtils;
import com.ecep.contract.ds.company.repository.CompanyOldNameRepository;
import com.ecep.contract.model.Company;
import com.ecep.contract.model.CompanyOldName;
import com.ecep.contract.util.MyStringUtils;
import com.ecep.contract.util.SpecificationUtils;
@Lazy
@Service
public class CompanyOldNameService implements IEntityService<CompanyOldName> {
private static final Logger logger = LoggerFactory.getLogger(CompanyOldNameService.class);
@Lazy
@Autowired
private CompanyOldNameRepository companyOldNameRepository;
@Lazy
@Autowired
private CompanyService companyService;
public CompanyOldName findById(Integer id) {
return companyOldNameRepository.findById(id).orElse(null);
}
@Override
public Specification<CompanyOldName> getSpecification(String searchText) {
if (!StringUtils.hasText(searchText)) {
return null;
}
return SpecificationUtils.andWith(searchText, this::buildSearchSpecification);
}
protected Specification<CompanyOldName> buildSearchSpecification(String searchText) {
return (root, query, builder) -> {
return builder.or(
builder.like(root.get("name"), "%" + searchText + "%"),
builder.like(root.get("memo"), "%" + searchText + "%")
);
};
}
public CompanyOldName save(CompanyOldName companyOldName) {
return companyOldNameRepository.save(companyOldName);
}
public boolean makePathAbsent(CompanyOldName companyOldName) {
String path = companyOldName.getPath();
if (StringUtils.hasText(path)) {
File file = new File(path);
if (file.exists()) {
return false;
}
}
File dir = makePath(companyOldName);
if (dir == null) {
return false;
}
if (!dir.exists()) {
return false;
}
companyOldName.setPath(dir.getAbsolutePath());
return true;
}
public File makePath(CompanyOldName companyOldName) {
String oldName = companyOldName.getName();
File basePath = companyService.getBasePath();
Company company = companyService.findById(companyOldName.getCompanyId());
String district = company.getDistrict();
if (StringUtils.hasText(district)) {
String parentPrefix = CompanyFileUtils.getParentPrefixByDistrict(district);
if (parentPrefix != null) {
File parent = new File(basePath, parentPrefix);
if (!parent.exists()) {
if (!parent.mkdir()) {
return null;
}
}
String fileName = CompanyFileUtils.escapeFileName(oldName);
File dir = new File(parent, fileName);
if (!dir.exists()) {
if (!dir.mkdir()) {
return null;
}
}
return dir;
}
}
return null;
}
public List<CompanyOldName> findAllByName(String name) {
return companyOldNameRepository.findAllByName(name);
}
public List<CompanyOldName> findAll(Specification<CompanyOldName> spec, Sort sort) {
return companyOldNameRepository.findAll(spec, sort);
}
public List<CompanyOldName> findAllByCompany(Company company) {
return companyOldNameRepository.findAllByCompanyId(company.getId());
}
public CompanyOldName findMatchByDate(Company company, LocalDate date) {
List<CompanyOldName> oldNames = findAllByCompany(company);
if (oldNames == null || oldNames.isEmpty()) {
return null;
}
return oldNames.stream().filter(v -> {
if (v.getAmbiguity()) {
return false;
}
if (v.getBeginDate() != null && date.isBefore(v.getBeginDate())) {
return false;
}
if (v.getEndDate() != null && date.isAfter(v.getEndDate())) {
return false;
}
return true;
}).findFirst().orElse(null);
}
public void deleteById(int id) {
companyOldNameRepository.deleteById(id);
}
public void delete(CompanyOldName entity) {
companyOldNameRepository.delete(entity);
}
public List<CompanyOldName> findAllByCompanyAndName(Company company, String oldName) {
return companyOldNameRepository.findAllByCompanyIdAndName(company.getId(), oldName);
}
/**
* 将 from 的曾用名 关联到 to
*
* @param from from
* @param to to
*/
public void resetTo(Company from, Company to) {
// 曾用名 关联到 to
List<CompanyOldName> list = companyOldNameRepository.findAllByCompanyId(from.getId());
if (list.isEmpty()) {
return;
}
for (CompanyOldName oldName : list) {
oldName.setMemo(MyStringUtils.appendIfAbsent(oldName.getMemo(), "转自 " + from.getId()));
oldName.setCompanyId(to.getId());
}
companyOldNameRepository.saveAll(list);
}
public void deleteByCompany(Company company) {
int deleted = companyOldNameRepository.deleteAllByCompanyId(company.getId());
if (deleted > 0) {
if (logger.isInfoEnabled()) {
logger.info("Delete {} records by company:#{}", deleted, company.getId());
}
}
}
/**
* 根据提供的搜索文本查询公司旧名称列表。
* <p>
* 该函数使用JPA的Specification接口构建查询条件查找公司旧名称中包含指定文本的记录。
* 查询结果最多返回10条记录。
*
* @param searchText 用于搜索的文本,将匹配公司旧名称中包含该文本的记录。
* @return 包含匹配的公司旧名称的列表列表中的每个元素都是一个CompanyOldName对象。
*/
public List<CompanyOldName> search(String searchText) {
return companyOldNameRepository.findAll(getSpecification(searchText), Pageable.ofSize(10)).getContent();
}
@Override
public Page<CompanyOldName> findAll(Specification<CompanyOldName> spec, Pageable pageable) {
return companyOldNameRepository.findAll(spec, pageable);
}
public CompanyOldName createNew(Company company, String name, boolean ambiguity) {
CompanyOldName companyOldName = new CompanyOldName();
companyOldName.setCompanyId(company.getId());
companyOldName.setName(name);
companyOldName.setAmbiguity(ambiguity);
return companyOldName;
}
}

View File

@@ -0,0 +1,607 @@
package com.ecep.contract.ds.company.service;
import java.io.File;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import com.ecep.contract.IEntityService;
import com.ecep.contract.MyDateTimeUtils;
import com.ecep.contract.cloud.rk.CloudRkService;
import com.ecep.contract.cloud.tyc.CloudTycService;
import com.ecep.contract.cloud.u8.YongYouU8Service;
import com.ecep.contract.constant.CompanyVendorConstant;
import com.ecep.contract.ds.company.CompanyFileUtils;
import com.ecep.contract.ds.company.repository.CompanyRepository;
import com.ecep.contract.ds.contract.service.ContractService;
import com.ecep.contract.ds.customer.service.CompanyCustomerService;
import com.ecep.contract.ds.other.service.SysConfService;
import com.ecep.contract.ds.vendor.service.CompanyVendorService;
import com.ecep.contract.model.Company;
import com.ecep.contract.model.CompanyCustomer;
import com.ecep.contract.model.CompanyOldName;
import com.ecep.contract.model.CompanyVendor;
import com.ecep.contract.util.MyStringUtils;
import com.ecep.contract.util.SpecificationUtils;
import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.Path;
import jakarta.persistence.criteria.Predicate;
import jakarta.transaction.Transactional;
/**
* 公司服务
*/
@Lazy
@Service
@CacheConfig(cacheNames = "company")
public class CompanyService implements IEntityService<Company> {
private static final Logger logger = LoggerFactory.getLogger(CompanyService.class);
private static final String COMPANY_BASE_PATH = "company.base.path";
@Lazy
@Autowired
private CompanyRepository companyRepository;
@Lazy
@Autowired
private SysConfService confService;
@Lazy
@Autowired
private CompanyFileService companyFileService;
@Lazy
@Autowired
private ContractService contractService;
@Lazy
@Autowired
private CompanyVendorService companyVendorService;
@Lazy
@Autowired
private CompanyCustomerService companyCustomerService;
@Lazy
@Autowired
private CompanyOldNameService companyOldNameService;
@Lazy
@Autowired
private CompanyContactService companyContactService;
@Lazy
@Autowired
private CloudRkService cloudRkService;
@Lazy
@Autowired
private CloudTycService cloudTycService;
@Lazy
@Autowired(required = false)
private YongYouU8Service yongYouU8Service;
@Cacheable(key = "#p0")
public Company findById(Integer id) {
return companyRepository.findById(id).orElse(null);
}
@Cacheable(key = "'name-'+#p0")
public Company findByName(String name) {
return companyRepository.findFirstByName(name).orElse(null);
}
/**
* 查找名称是 name 的记录
*
* @param name 查询的公司名称
* @return 记录列表
*/
public List<Company> findAllByName(String name) {
return companyRepository.findAllByName(name);
}
public Page<Company> findAll(Specification<Company> spec, Pageable pageable) {
return companyRepository.findAll(spec, pageable);
}
/**
* 查找
* 重复的删除
*
* @param uniscid 统一社会信用代码
* @return 公司对象
*/
public Company findAndRemoveDuplicateCompanyByUniscid(String uniscid) {
// 根据统一社会信用代码去查询
List<Company> companies = companyRepository.findAllByUniscid(uniscid);
if (companies.isEmpty()) {
return null;
}
if (companies.size() == 1) {
return companies.getFirst();
} else {
List<Company> result = removeDuplicatesByUniscid(companies);
if (!result.isEmpty()) {
return result.getFirst();
}
}
return null;
}
/**
* 查找公司,根据名称或简称查询
* <p>
* 1. 先按照 name 查找Company记录如果有多个记录只保留一条保留规则参考 #removeDuplicatesByUniscid 方法
* 2. 第一步没有匹配到时,根据名称从曾用名中查询
* 3. 上一步没有匹配到时,根据简称从公司数据库查询匹配简称的公司
* 4. 上一步没有匹配到时,根据简称从曾用名中查询
* 根据简称去查询,如果有多个记录只保留一条,保留规则参考 #removeDuplicatesByUniscid 方法
* 重复的删除
*
* @param name 企业名称
* @param abbName 别名
* @return 公司对象
*/
public Company findAndRemoveDuplicateCompanyByNameOrAbbName(String name, String abbName) {
Company updater = null;
{
// 根据公司全名去查询
List<Company> companies = companyRepository.findAllByName(name);
if (companies.isEmpty()) {
if (logger.isDebugEnabled()) {
logger.debug("No record match by {}", name);
}
} else if (companies.size() == 1) {
updater = companies.getFirst();
} else {
List<Company> result = removeDuplicatesByUniscid(companies);
if (!result.isEmpty()) {
updater = result.getFirst();
}
}
}
if (updater == null) {
// 根据公司名称去曾用名中查询
List<CompanyOldName> oldNames = companyOldNameService.findAllByName(name);
if (!oldNames.isEmpty()) {
CompanyOldName oldName = oldNames.getFirst();
Optional<Company> optional = companyRepository.findById(oldName.getCompanyId());
if (optional.isPresent()) {
updater = optional.get();
}
}
}
if (updater == null && StringUtils.hasText(abbName) && !Objects.equals(abbName, name)) {
// 根据公司全面去查询
List<Company> companies = companyRepository.findAllByShortName(abbName);
if (!companies.isEmpty()) {
updater = companies.removeFirst();
}
if (updater == null) {
// 根据公司名称去曾用名中查询
List<CompanyOldName> oldNames = companyOldNameService.findAllByName(abbName);
if (!oldNames.isEmpty()) {
CompanyOldName oldName = null;
Optional<CompanyOldName> optional1 = oldNames.stream().filter(CompanyOldName::getAmbiguity)
.findFirst();
oldName = optional1.orElseGet(oldNames::getFirst);
Optional<Company> optional = companyRepository.findById(oldName.getCompanyId());
if (optional.isPresent()) {
updater = optional.get();
}
}
}
}
return updater;
}
/**
* 删除 列表中 Uniscid 重复的
*/
private List<Company> removeDuplicatesByUniscid(List<Company> list) {
List<Company> result = new ArrayList<>();
List<Company> removes = new ArrayList<>();
Set<String> uniqueUniscidSet = new HashSet<>();
for (Company company : list) {
// 名称相同后,统一社会信用编号 也相同的话,删除
if (uniqueUniscidSet.add(company.getUniscid())) {
// 没有记录过时
result.add(company);
} else {
// 有重复时
removes.add(company);
}
}
Company updater = result.getFirst();
// 合并重复的
for (Company company : removes) {
try {
merge(company, updater);
} catch (Exception e) {
logger.error("合并 {} -> {} 时发生错误:{}", company.toPrettyString(), updater.toPrettyString(), e.getMessage(),
e);
throw e;
}
}
return result;
}
/**
* 删除
* <p>
* 删除前需要把关联数据解除
* <ul>
* <li>{@link CompanyVendorService#deleteByCompany(Company)}</li>
* <li>{@link CompanyCustomerService#deleteByCompany(Company)}</li>
* <li>{@link CompanyOldNameService#deleteByCompany(Company)}</li>
* <li>{@link CompanyContactService#deleteByCompany(Company)}</li>
* <li>{@link ContractService#deleteByCompany(Company)}</li>
* <li>{@link CompanyContactService#deleteByCompany(Company)}</li>
* </ul>
* 或者 把关联数据转移到其他公司
* <ul>
* <li>{@link CompanyVendorService#resetTo(Company, Company)}</li>
* <li>{@link CompanyCustomerService#resetTo(Company, Company)}</li>
* <li>{@link CompanyOldNameService#resetTo(Company, Company)}</li>
* <li>{@link CompanyContactService#resetTo(Company, Company)}</li>
* <li>{@link ContractService#resetTo(Company, Company)}</li>
* <li>{@link CompanyContactService#resetTo(Company, Company)}</li>
* </ul>
* </p>
*
* @param company 要删除的公司对象
*/
@Caching(evict = {
@CacheEvict(key = "#p0.id"),
@CacheEvict(key = "'name-'+#p0.name")
})
public void delete(Company company) {
cloudRkService.deleteByCompany(company);
cloudTycService.deleteByCompany(company);
yongYouU8Service.deleteByCompany(company);
companyOldNameService.deleteByCompany(company);
companyContactService.deleteByCompany(company);
// 供应商和客户
companyVendorService.deleteByCompany(company);
companyCustomerService.deleteByCompany(company);
contractService.deleteByCompany(company);
companyContactService.deleteByCompany(company);
companyRepository.delete(company);
if (logger.isInfoEnabled()) {
logger.info("Delete Company {}", company);
}
}
/**
* 合并 from 到 to
* <p>
* 下述关联数据重设绑定到 to
* <ol>
* <li>曾用名</li>
* <li>供应商</li>
* <li>客户</li>
* <li>合同</li>
* <li>公司合同</li>
* </ol>
* </p>
*/
public void merge(Company from, Company to) {
// cloudRkService.findById(from.getId());
cloudRkService.resetTo(from, to);
cloudTycService.resetTo(from, to);
yongYouU8Service.resetTo(from, to);
companyOldNameService.resetTo(from, to);
companyContactService.resetTo(from, to);
// 供应商和客户
companyVendorService.resetTo(from, to);
companyCustomerService.resetTo(from, to);
contractService.resetTo(from, to);
companyContactService.resetTo(from, to);
companyRepository.delete(from);
if (logger.isInfoEnabled()) {
logger.info("Merge {} to {}", from, to);
}
}
/**
* 保存实体对象,异步方法
*
* @param company 要保存的实体对象
* @return 返回异步调用
*/
public CompletableFuture<Company> asyncSave(Company company) {
return CompletableFuture.completedFuture(companyRepository.save(company));
}
/**
* 保存实体对象
*
* @param company 要保存的实体对象
* @return 返回异步调用
*/
@Caching(evict = {
@CacheEvict(key = "#p0.id"),
@CacheEvict(key = "'name-'+#p0.name")
})
public Company save(Company company) {
return companyRepository.save(company);
}
public long count() {
return companyRepository.count();
}
public long count(Specification<Company> spec) {
return companyRepository.count(spec);
}
@Transactional
public void findAllWithStream(Consumer<Stream<Company>> consumer) {
try (Stream<Company> stream = companyRepository.findAllAsStream()) {
consumer.accept(stream);
}
}
public File getVendorBasePath() {
return new File(confService.getString(CompanyVendorConstant.KEY_BASE_PATH));
}
public File getCustomerBasePath() {
return new File(confService.getString(CompanyCustomerService.KEY_BASE_PATH));
}
public File getBasePath() {
return new File(confService.getString(COMPANY_BASE_PATH));
}
/**
* 创建公司目录,如果公司目录未设置,或者未存在
*
* @param company 要创建目录的公司对象
* @return 是否创建了目录
*/
public boolean makePathAbsent(Company company) {
String path = company.getPath();
if (StringUtils.hasText(path)) {
File file = new File(path);
if (file.exists()) {
return false;
}
}
File dir = makePath(company);
if (dir == null) {
return false;
}
if (!dir.exists()) {
return false;
}
company.setPath(dir.getAbsolutePath());
company.setPathExist(true);
return true;
}
/**
* 创建企业目录
*
* @param company 要创建的企业对象
* @return 目录
*/
public File makePath(Company company) {
File basePath = getBasePath();
if (!basePath.exists()) {
return null;
}
String companyName = company.getName();
String district = company.getDistrict();
if (StringUtils.hasText(district)) {
String parentPrefix = CompanyFileUtils.getParentPrefixByDistrict(district);
if (parentPrefix != null) {
File parent = new File(basePath, parentPrefix);
if (!parent.exists()) {
if (!parent.mkdir()) {
return null;
}
}
String fileName = CompanyFileUtils.escapeFileName(companyName);
File dir = new File(parent, fileName);
if (!dir.exists()) {
if (!dir.mkdir()) {
return null;
}
}
return dir;
}
}
return null;
}
/**
* 移动文件到企业目录下
*
* @param company 企业对象
* @param files 要被移动的文件集合,需要从中选择需要的
* @param status 状态输出
*/
public boolean retrieveFromDownloadFiles(Company company, File[] files, Consumer<String> status) {
//
boolean companyChanged = makePathAbsent(company);
if (!StringUtils.hasText(company.getPath())) {
// fixed 要退出,需要保存
if (companyChanged) {
save(company);
}
status.accept("存储目录未设置,请检查");
return false;
}
File home = new File(company.getPath());
if (!home.exists()) {
// fixed 要退出,需要保存
if (companyChanged) {
company = save(company);
}
status.accept(company.getPath() + " 不存在,无法访问,请检查或者修改");
return false;
}
boolean retrieved = companyFileService.retrieveFromDownloadFiles(company, files, status);
if (companyChanged) {
save(company);
}
return retrieved;
}
/**
* 验证企业状态
*
* @param company 要验证的公司
* @param verifyDate 验证日期
* @param status 状态输出
*/
public void verifyEnterpriseStatus(Company company, LocalDate verifyDate, Consumer<String> status) {
// 检查营业状态
String entStatus = company.getEntStatus();
if (StringUtils.hasText(entStatus)) {
if (entStatus.contains("注销")) {
LocalDate end = company.getOperationPeriodEnd();
LocalDate begin = company.getOperationPeriodBegin();
if (begin == null || end == null) {
// 注销时间未知,无法判断是否在 verifyDate 之后注销
status.accept("营业状态异常:" + entStatus);
} else {
if (!MyDateTimeUtils.dateValidFilter(verifyDate, begin, end, 0)) {
status.accept("营业状态异常:" + entStatus);
}
}
}
} else {
status.accept("营业状态异常:未设置");
}
}
@Override
public Specification<Company> getSpecification(String searchText) {
if (!StringUtils.hasText(searchText)) {
return null;
}
// 判断是否全是数字
boolean isAllDigit = MyStringUtils.isAllDigit(searchText);
if (isAllDigit) {
return (root, query, builder) -> {
return builder.or(
builder.like(root.get("id").as(String.class), "%" + searchText + "%"),
builder.like(root.get("uniscid"), "%" + searchText + "%"));
};
}
Specification<Company> spec = null;
Set<Integer> idSet = companyOldNameService.search(searchText).stream().map(CompanyOldName::getCompanyId)
.collect(Collectors.toSet());
if (!idSet.isEmpty()) {
spec = SpecificationUtils.or(spec, (root, query, builder) -> {
return root.get("id").in(idSet);
});
}
List<CompanyVendor> searchedVendors = companyVendorService.search(searchText);
if (!searchedVendors.isEmpty()) {
spec = SpecificationUtils.or(spec, (root, query, builder) -> {
return builder.in(root.get("id")).value(searchedVendors.stream()
.map(CompanyVendor::getCompany)
.filter(Objects::nonNull)
.map(Company::getId)
.collect(Collectors.toSet()));
});
}
List<CompanyCustomer> searchedCustomers = companyCustomerService.search(searchText);
if (!searchedCustomers.isEmpty()) {
spec = SpecificationUtils.or(spec, (root, query, builder) -> {
return builder.in(root.get("id")).value(searchedCustomers.stream()
.map(CompanyCustomer::getCompany)
.filter(Objects::nonNull)
.map(Company::getId)
.collect(Collectors.toSet()));
});
}
return SpecificationUtils.or(spec, SpecificationUtils.andWith(searchText, this::buildSearchSpecification));
}
protected Specification<Company> buildSearchSpecification(String searchText) {
return (root, query, builder) -> buildSearchPredicate(searchText, root, query, builder);
}
public Predicate buildSearchPredicate(String searchText, Path<Company> root, @Nullable CriteriaQuery<?> query,
CriteriaBuilder builder) {
return builder.or(
builder.like(root.get("name"), "%" + searchText + "%"),
builder.like(root.get("shortName"), "%" + searchText + "%"),
builder.like(root.get("uniscid"), "%" + searchText + "%"),
builder.like(root.get("legalRepresentative"), "%" + searchText + "%"),
builder.like(root.get("regAddr"), "%" + searchText + "%"),
builder.like(root.get("address"), "%" + searchText + "%"),
builder.like(root.get("memo"), "%" + searchText + "%"));
}
/**
* 检索企业
* 企业名称中模糊搜索
*
* @param searchText 搜索文本
* @return 企业列表返回前10个企业
*/
public List<Company> search(String searchText) {
Specification<Company> spec = getSpecification(searchText);
return companyRepository.findAll(spec, Pageable.ofSize(10)).getContent();
}
public Company createNewCompany(String name) {
Company company = new Company();
company.setName(name);
company.setCreated(LocalDate.now());
return company;
}
public List<String> getAllNames(Company company) {
List<String> list = new ArrayList<>();
list.add(company.getName());
companyOldNameService.findAllByCompany(company).forEach(oldName -> {
// 歧义的曾用名不采用
if (oldName.getAmbiguity()) {
return;
}
list.add(oldName.getName());
});
return list;
}
}

View File

@@ -0,0 +1,75 @@
package com.ecep.contract.ds.company.service;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import com.ecep.contract.IEntityService;
import com.ecep.contract.ds.company.repository.InvoiceRepository;
import com.ecep.contract.model.Invoice;
@Lazy
@Service
@CacheConfig(cacheNames = "invoice")
public class InvoiceService implements IEntityService<Invoice> {
private static final Logger logger = LoggerFactory.getLogger(InvoiceService.class);
@Autowired
private InvoiceRepository repository;
@Cacheable(key = "#p0")
public Invoice findById(Integer id) {
return repository.findById(id).orElse(null);
}
@Override
public Specification<Invoice> getSpecification(String searchText) {
if (!StringUtils.hasText(searchText)) {
return null;
}
return (root, query, builder) -> {
return builder.or(
builder.like(root.get("code"), "%" + searchText + "%"),
builder.like(root.get("description"), "%" + searchText + "%")
);
};
}
@Override
public Page<Invoice> findAll(Specification<Invoice> spec, Pageable pageable) {
return repository.findAll(spec, pageable);
}
@CacheEvict(key = "#p0.id")
public void delete(Invoice entity) {
repository.delete(entity);
}
public List<Invoice> findAll(Specification<Invoice> spec, Sort by) {
return repository.findAll(spec, by);
}
public Invoice findByCode(String invoiceNumber) {
return repository.findByCode(invoiceNumber);
}
@CacheEvict(key = "#p0.id")
public Invoice save(Invoice invoice) {
return repository.save(invoice);
}
}

View File

@@ -0,0 +1,150 @@
package com.ecep.contract.ds.company.tasker;
import java.time.Instant;
import java.time.LocalDate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import com.ecep.contract.MessageHolder;
import com.ecep.contract.cloud.rk.CloudRkService;
import com.ecep.contract.cloud.rk.ctx.CloudRkCtx;
import com.ecep.contract.cloud.tyc.CloudTycService;
import com.ecep.contract.cloud.u8.YongYouU8Service;
import com.ecep.contract.cloud.u8.ctx.CompanyCtx;
import com.ecep.contract.cloud.u8.ctx.ContractCtx;
import com.ecep.contract.cloud.u8.ctx.CustomerCtx;
import com.ecep.contract.cloud.u8.ctx.VendorCtx;
import com.ecep.contract.constant.CloudServiceConstant;
import com.ecep.contract.model.CloudRk;
import com.ecep.contract.model.CloudYu;
import com.ecep.contract.model.Company;
import com.ecep.contract.ui.Tasker;
import lombok.Setter;
/**
* 合并更新
*/
public class CompanyCompositeUpdateTasker extends Tasker<Object> {
private static final Logger logger = LoggerFactory.getLogger(CompanyCompositeUpdateTasker.class);
CloudRkCtx cloudRkCtx = new CloudRkCtx();
@Setter
private CloudRkService cloudRkService;
@Setter
private CloudTycService cloudTycService;
@Setter
private YongYouU8Service yongYouU8Service;
@Setter
private Company company;
@Override
protected Object execute(MessageHolder holder) throws Exception {
updateProgress(0.1, 1);
syncFromCloudRk(holder);
updateProgress(0.3, 1);
syncFromYongYouU8(holder);
updateProgress(0.6, 1);
syncFromCloudTyc(holder);
return null;
}
private void syncFromCloudRk(MessageHolder holder) {
holder.debug("1. 从 " + CloudServiceConstant.RK_NAME + " 更新...");
try {
cloudRkService = getBean(CloudRkService.class);
} catch (BeansException e) {
holder.warn("未启用 " + CloudServiceConstant.RK_NAME + " 服务");
return;
}
CloudRk cloudRk = cloudRkService.getOrCreateCloudRk(company);
if (cloudRk == null) {
holder.error("无法创建或获取 CloudRk 对象");
return;
}
try {
cloudRkCtx.setCloudRkService(cloudRkService);
if (cloudRkCtx.syncCompany(company, cloudRk, holder)) {
}
} catch (Exception e) {
cloudRk.setDescription(e.getMessage());
} finally {
cloudRk.setLatestUpdate(Instant.now());
cloudRkService.save(cloudRk);
}
}
private void syncFromYongYouU8(MessageHolder holder) {
holder.debug("2. 从 " + CloudServiceConstant.U8_NAME + " 更新...");
try {
yongYouU8Service = getBean(YongYouU8Service.class);
} catch (BeansException e) {
holder.warn("未启用 " + CloudServiceConstant.U8_NAME + " 服务");
return;
}
CloudYu cloudYu = yongYouU8Service.getOrCreateCloudYu(company);
if (cloudYu == null) {
holder.error("无法创建或获取 CloudYu 对象");
return;
}
try {
CompanyCtx companyCtx = new CompanyCtx();
yongYouU8Service.initialize(companyCtx);
if (companyCtx.syncCompany(company, holder)) {
holder.info("更新");
}
VendorCtx vendorCtx = new VendorCtx();
yongYouU8Service.initialize(vendorCtx);
vendorCtx.setCompanyCtx(companyCtx);
if (vendorCtx.syncVendor(company, holder)) {
cloudYu.setVendorUpdateDate(LocalDate.now());
}
CustomerCtx customerCtx = new CustomerCtx();
yongYouU8Service.initialize(customerCtx);
customerCtx.setCompanyCtx(companyCtx);
if (customerCtx.syncCustomer(company, holder)) {
cloudYu.setCustomerUpdateDate(LocalDate.now());
}
ContractCtx contractCtx = new ContractCtx();
yongYouU8Service.initialize(contractCtx);
contractCtx.syncContract(company, holder);
cloudYu.setCloudLatest(Instant.now());
cloudYu.setExceptionMessage("");
} catch (Exception e) {
String message = e.getMessage();
holder.error("同步过程中发生错误: " + message);
// 保留255个字符
if (message.length() > 255) {
message = message.substring(0, 255);
}
cloudYu.setExceptionMessage(message);
} finally {
cloudYu.setLatestUpdate(Instant.now());
yongYouU8Service.save(cloudYu);
}
}
private void syncFromCloudTyc(MessageHolder holder) {
holder.debug("3. 从 " + CloudServiceConstant.TYC_NAME + " 更新...");
try {
cloudTycService = getBean(CloudTycService.class);
} catch (BeansException e) {
holder.warn("未启用 " + CloudServiceConstant.TYC_NAME + " 服务");
return;
}
cloudTycService.syncCompany(company, holder);
updateProgress(1, 1);
}
}

View File

@@ -0,0 +1,72 @@
package com.ecep.contract.ds.company.tasker;
import java.util.concurrent.atomic.AtomicInteger;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import com.ecep.contract.MessageHolder;
import com.ecep.contract.ds.company.service.CompanyFileService;
import com.ecep.contract.model.Company;
import com.ecep.contract.ui.Tasker;
/**
* 对所有公司的文件进行重置
*/
public class CompanyFilesRebuildTasker extends Tasker<Object> {
private CompanyFileService companyFileService;
public CompanyFilesRebuildTasker() {
updateTitle("合同文件重置");
}
@Override
protected Object execute(MessageHolder holder) throws Exception {
Pageable pageRequest = PageRequest.ofSize(200);
AtomicInteger counter = new AtomicInteger(0);
Specification<Company> spec = null;
// Specification<Contract> spec = (root, query, cb) -> {
// return cb.greaterThan(root.get("created"), Instant.now().minusSeconds(TimeUnit.DAYS.toSeconds(360)));
// };
updateTitle("遍历所有公司,对每个可以公司的文件进行“重置”操作");
long total = getCompanyService().count(spec);
while (true) {
if (isCancelled()) {
break;
}
Page<Company> page = getCompanyService().findAll(spec, pageRequest);
if (page.isEmpty()) {
break;
}
for (Company company : page) {
if (isCancelled()) {
break;
}
String prefix = counter.get() + " / " + total + "> " + company.getName() + " #" + company.getId() + "> ";
getCompanyFileService().reBuildingFiles(company, holder.sub(prefix)::info);
updateProgress(counter.incrementAndGet(), total);
}
if (!page.hasNext()) {
break;
}
pageRequest = page.nextPageable();
}
return super.call();
}
private CompanyFileService getCompanyFileService() {
if (companyFileService == null) {
companyFileService = getBean(CompanyFileService.class);
}
return companyFileService;
}
}

View File

@@ -0,0 +1,93 @@
package com.ecep.contract.ds.company.tasker;
import java.time.LocalDate;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import com.ecep.contract.MessageHolder;
import com.ecep.contract.ds.company.service.CompanyService;
import com.ecep.contract.ds.contract.tasker.ContractVerifyComm;
import com.ecep.contract.model.Company;
import com.ecep.contract.model.Contract;
import com.ecep.contract.ui.Tasker;
import lombok.Getter;
import lombok.Setter;
public class CompanyVerifyTasker extends Tasker<Object> {
@Setter
private CompanyService companyService;
@Getter
@Setter
private Company company;
ContractVerifyComm comm = new ContractVerifyComm();
AtomicBoolean verified = new AtomicBoolean(true);
public CompanyService getCompanyService() {
if (companyService == null) {
companyService = getBean(CompanyService.class);
}
return companyService;
}
@Override
public Object call() throws Exception {
comm.setVerifyCompanyPath(false);
comm.setVerifyCompanyStatus(false);
comm.setVerifyCompanyCredit(false);
return execute(new MessageHolderImpl() {
@Override
public void addMessage(Level level, String message) {
super.addMessage(level, message);
if (level.intValue() > Level.INFO.intValue()) {
verified.set(false);
}
}
});
}
@Override
protected Object execute(MessageHolder holder) throws Exception {
updateTitle("验证企业是否符合合规要求");
verify(company, holder);
if (verified.get()) {
updateMessage(Level.CONFIG, "合规验证通过");
} else {
updateMessage(Level.SEVERE, "合规验证不通过");
}
return null;
}
/**
* 核验公司名下的所有合同
*
* @param company 公司
* @param holder 输出
*/
private void verify(Company company, MessageHolder holder) {
LocalDate now = LocalDate.now();
getCompanyService().verifyEnterpriseStatus(company, now, holder::info);
// 验证所有的合同
List<Contract> list = comm.getContractService().findAllByCompany(company);
if (list.isEmpty()) {
holder.debug("!没有相关合同!");
return;
}
holder.debug("检索到相关合同 " + list.size() + "");
AtomicInteger counter = new AtomicInteger(0);
long total = list.size();
for (Contract contract : list) {
holder.debug("核验合同:" + contract.getCode() + ", " + contract.getName());
comm.verify(company, contract, holder.sub("-- "));
updateProgress(counter.incrementAndGet(), total);
}
updateProgress(1, 1);
}
}

View File

@@ -0,0 +1,30 @@
package com.ecep.contract.ds.contract;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import com.ecep.contract.ds.contract.service.ContractService;
import com.ecep.contract.model.Contract;
import com.ecep.contract.util.EntityStringConverter;
import jakarta.annotation.PostConstruct;
@Lazy
@Component
public class ContractStringConverter extends EntityStringConverter<Contract> {
@Lazy
@Autowired
ContractService service;
public ContractStringConverter() {
}
@PostConstruct
private void init() {
setInitialized(project -> service.findById(project.getId()));
setSuggestion(service::search);
// TODO 按名称找出,容易出问题
setFromString(service::findByName);
}
}

View File

@@ -0,0 +1,48 @@
#
# drop table if exists CONTRACT_COST;
create table if not exists PROJECT_COST
(
ID int auto_increment
primary key,
CONTRACT_ID int null comment '合同编号',
PROJECT_ID int null comment '项目编号',
APPLY_DATE date null comment '申请日期',
STANDARD_CONTRACT_TEXT bit default b'0' not null comment '是否是标准合同文本',
STANDARD_PAY_WAY bit default b'0' not null comment '是否是标准付款方式',
NO_STANDARD_PAY_WAY_TEXT varchar(255) null comment '非标准付款方式文本',
NO_STANDARD_CONTRACT_TEXT varchar(255) null comment '非标准合同文本',
ON_SITE_POSITION_FEE float default 0 not null comment '现场就位费',
ON_SITE_SERVICE_FEE float default 0 not null comment '现场服务费',
ASSEMBLY_SERVICE_FEE float default 0 not null comment '装机服务费',
TECHNICAL_SERVICE_FEE float default 0 not null comment '技术服务费',
BID_SERVICE_FEE float default 0 not null comment '投标服务费',
FREIGHT_COST float default 0 not null comment '运费',
GUARANTEE_LETTER_FEE float default 0 not null comment '保函费',
TAX_AND_SURCHARGES float default 0 not null comment '营业税及附加费',
GROSS_PROFIT_MARGIN double default 0 not null comment '毛利率',
IN_EXCLUSIVE_TAX_AMOUNT double default 0 not null comment '不含税进项总金额',
IN_QUANTITY double default 0 not null comment '进项总数',
IN_TAX_AMOUNT double default 0 not null comment '含税进项总金额',
OUT_EXCLUSIVE_TAX_AMOUNT double default 0 not null comment '不含税出项总金额',
OUT_QUANTITY double default 0 not null comment '出项总数',
OUT_TAX_AMOUNT double default 0 not null comment '含税出项总金额',
constraint CONTRACT_COST_CONTRACT_ID_fk
foreign key (CONTRACT_ID) references CONTRACT (ID),
constraint PROJECT_COST_PROJECT_ID_fk
foreign key (PROJECT_ID) references PROJECT (ID)
)
comment '项目的成本';
/***
转换为项目成本
*/
select A.ID, A.PROJECT_ID,C.ID, P.ID from PROJECT_COST as A left join CONTRACT as C on A.CONTRACT_ID = C.ID left join PROJECT as P on C.PROJECT_ID = P.ID
select pc1_0.ID,pc1_0.APPLICANT_ID,pc1_0.APPLY_DATE,pc1_0.ASSEMBLY_SERVICE_FEE,pc1_0.AUTHORIZER_FILE,pc1_0.AUTHORIZER_DATE,pc1_0.AUTHORIZER_ID,pc1_0.BID_SERVICE_FEE,pc1_0.CONTRACT_ID,pc1_0.DESCRIPTION,pc1_0.FREIGHT_COST,pc1_0.GROSS_PROFIT_MARGIN,pc1_0.GUARANTEE_LETTER_FEE,pc1_0.IMPORT_LOCK,pc1_0.IN_EXCLUSIVE_TAX_AMOUNT,pc1_0.IN_QUANTITY,pc1_0.IN_TAX_AMOUNT,pc1_0.NO_STANDARD_CONTRACT_TEXT,pc1_0.NO_STANDARD_PAY_WAY_TEXT,pc1_0.ON_SITE_SERVICE_FEE,pc1_0.OUT_EXCLUSIVE_TAX_AMOUNT,pc1_0.OUT_QUANTITY,pc1_0.OUT_TAX_AMOUNT,pc1_0.PROJECT_ID,pc1_0.STAMP_TAX,pc1_0.STAMP_TAX_FEE,pc1_0.STANDARD_CONTRACT_TEXT,pc1_0.STANDARD_PAY_WAY,pc1_0.TAX_AND_SURCHARGES,pc1_0.TAX_AND_SURCHARGES_FEE,pc1_0.TECHNICAL_SERVICE_FEE,pc1_0.VER
from PROJECT_COST pc1_0 where pc1_0.DESCRIPTION like ? escape '' and pc1_0.PROJECT_ID=274

View File

@@ -0,0 +1,31 @@
CREATE TABLE IF NOT EXISTS CONTRACT_COST_ITEM
(
ID INT AUTO_INCREMENT NOT NULL,
COST_ID INT NULL comment '合同成本id',
TITLE VARCHAR(255) NULL comment '名称',
SPECIFICATION VARCHAR(255) NULL comment '规格',
UNIT VARCHAR(255) NULL comment '单位',
IN_EX_TAX_PRICE double default 0 not null comment '不含税进项单价',
IN_TAX_RATE double default 0 not null comment '进项税率',
IN_TAX_PRICE double default 0 not null comment '不含税进项总价',
IN_QUANTITY double default 0 not null comment '进项数量',
OUT_EX_TAX_PRICE double default 0 not null comment '不含税出项单价',
OUT_TAX_RATE double default 0 not null comment '出项税率',
OUT_TAX_PRICE double default 0 not null comment '不含税出项总价',
OUT_QUANTITY double default 0 not null comment '出项数量',
REMARK VARCHAR(255) NULL comment '备注',
CREATE_TIME DATETIME NULL comment '创建时间',
CREATE_BY INT NULL comment '创建人',
UPDATE_TIME DATETIME NULL comment '更新时间',
UPDATE_BY INT NULL comment '更新人',
CONSTRAINT pk_contract_cost_item PRIMARY KEY (ID)
);
ALTER TABLE PROJECT_COST_ITEM
ADD CONSTRAINT FK_CONTRACT_COST_ITEM_ON_COST FOREIGN KEY (COST_ID) REFERENCES PROJECT_COST (ID);
ALTER TABLE PROJECT_COST_ITEM
ADD CONSTRAINT FK_CONTRACT_COST_ITEM_ON_CREATE_BY FOREIGN KEY (CREATE_BY) REFERENCES EMPLOYEE (ID);
ALTER TABLE PROJECT_COST_ITEM
ADD CONSTRAINT FK_CONTRACT_COST_ITEM_ON_UPDATE_BY FOREIGN KEY (UPDATE_BY) REFERENCES EMPLOYEE (ID);

View File

@@ -0,0 +1,76 @@
create table SALES_BILL_VOUCHER
(
ID int auto_increment
primary key,
CODE varchar(255) null,
DESCRIPTION text null,
EMPLOYEE_ID int null,
MAKER_ID int null,
MAKER_DATE datetime null,
VERIFIER_ID int null,
MODIFY_DATE datetime null,
VERIFIER_DATE datetime null,
REF_ID int default 0 not null,
COMPANY_ID int null,
constraint SALES_BILL_VOUCHER_COMPANY_ID_fk
foreign key (COMPANY_ID) references COMPANY (ID)
on delete set null,
constraint SALES_BILL_VOUCHER_EMPLOYEE_ID_fk
foreign key (MAKER_ID) references EMPLOYEE (ID)
on delete set null,
constraint SALES_BILL_VOUCHER_EMPLOYEE_ID_fk_2
foreign key (VERIFIER_ID) references EMPLOYEE (ID)
on delete set null,
constraint SALES_BILL_VOUCHER_EMPLOYEE_ID_fk_3
foreign key (EMPLOYEE_ID) references EMPLOYEE (ID)
on delete set null
);
create table SALES_BILL_VOUCHER_ITEM
(
ID int auto_increment
primary key,
REF_ID int default 0 not null,
VOUCHER_ID int null,
INVENTORY_ID int null,
DESCRIPTION text null,
QUANTITY double default 0 not null,
PRICE double default 0 not null,
constraint SALES_BILL_VOUCHER_ITEM_INVENTORY_ID_fk
foreign key (INVENTORY_ID) references INVENTORY (ID)
on delete set null,
constraint SALES_BILL_VOUCHER_ITEM_SALES_BILL_VOUCHER_ID_fk
foreign key (VOUCHER_ID) references SALES_BILL_VOUCHER (ID)
on delete cascade
);
/**
* 获取采购单的采购单
*/
select V.*
from PURCHASE_BILL_VOUCHER as V
join (select distinct VI.VOUCHER_ID
from PURCHASE_BILL_VOUCHER_ITEM as VI
left join PURCHASE_ORDER_ITEM as OI on VI.PURCHASE_ORDER_ITEM_ID = OI.ID
where ORDER_ID = 159) as U on V.ID = U.VOUCHER_ID;
/**
* 获取采购单的采购单
*/
select pbv1_0.ID,
pbv1_0.CODE,
pbv1_0.COMPANY_ID,
pbv1_0.DESCRIPTION,
pbv1_0.EMPLOYEE_ID,
pbv1_0.INVOICE_ID,
pbv1_0.MAKER_ID,
pbv1_0.MAKER_DATE,
pbv1_0.MODIFY_DATE,
pbv1_0.REF_ID,
pbv1_0.VERIFIER_ID,
pbv1_0.VERIFIER_DATE
from PURCHASE_BILL_VOUCHER pbv1_0
where pbv1_0.ID in ((select distinct pbvi1_0.VOUCHER_ID
from PURCHASE_BILL_VOUCHER_ITEM pbvi1_0
left join PURCHASE_ORDER_ITEM oi1_0 on oi1_0.ID = pbvi1_0.PURCHASE_ORDER_ITEM_ID
where oi1_0.ORDER_ID = ?));

View File

@@ -0,0 +1,23 @@
package com.ecep.contract.ds.contract.repository;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.stereotype.Repository;
import com.ecep.contract.model.ContractBidVendor;
@Repository
public interface ContractBidVendorRepository extends
// JDBC interfaces
CrudRepository<ContractBidVendor, Integer>, PagingAndSortingRepository<ContractBidVendor, Integer>,
// JPA interfaces
JpaRepository<ContractBidVendor, Integer>, JpaSpecificationExecutor<ContractBidVendor> {
List<ContractBidVendor> findByContractId(Integer contractId);
List<ContractBidVendor> findByContractIdAndCompanyId(Integer contractId, Integer companyId);
}

View File

@@ -0,0 +1,17 @@
package com.ecep.contract.ds.contract.repository;
import java.util.Optional;
import org.springframework.stereotype.Repository;
import com.ecep.contract.ds.MyRepository;
import com.ecep.contract.model.ContractCatalog;
@Repository
public interface ContractCatalogRepository extends MyRepository<ContractCatalog, Integer> {
Optional<ContractCatalog> findByCode(String code);
Optional<ContractCatalog> findByName(String name);
}

View File

@@ -0,0 +1,20 @@
package com.ecep.contract.ds.contract.repository;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.stereotype.Repository;
import com.ecep.contract.ContractFileType;
import com.ecep.contract.model.Contract;
import com.ecep.contract.model.ContractFile;
@Repository
public interface ContractFileRepository extends JpaRepository<ContractFile, Integer>, JpaSpecificationExecutor<ContractFile> {
List<ContractFile> findByContract(Contract contract);
List<ContractFile> findAllByContract(Contract contract);
List<ContractFile> findAllByContractAndType(Contract contract, ContractFileType type);
}

View File

@@ -0,0 +1,35 @@
package com.ecep.contract.ds.contract.repository;
import org.springframework.stereotype.Repository;
import com.ecep.contract.ContractFileType;
import com.ecep.contract.ds.other.repository.BaseEnumEntityRepository;
import com.ecep.contract.model.ContractFileTypeLocal;
@Repository
public interface ContractFileTypeLocalRepository
extends BaseEnumEntityRepository<ContractFileType, ContractFileTypeLocal, Integer> {
@Override
default ContractFileType[] getEnumConstants() {
return ContractFileType.values();
}
@Override
default ContractFileTypeLocal newEntity() {
return new ContractFileTypeLocal();
}
ContractFileTypeLocal findByTypeAndLang(ContractFileType type, String lang);
default ContractFileTypeLocal getCompleteByTypeAndLang(ContractFileType type, String lang) {
ContractFileTypeLocal v = findByTypeAndLang(type, lang);
if (v == null) {
v = newEntity();
v.setType(type);
v.setLang(lang);
v.setValue(type.name());
v = save(v);
}
return v;
}
}

View File

@@ -0,0 +1,18 @@
package com.ecep.contract.ds.contract.repository;
import java.util.Optional;
import org.springframework.stereotype.Repository;
import com.ecep.contract.ds.MyRepository;
import com.ecep.contract.model.ContractGroup;
@Repository
public interface ContractGroupRepository extends MyRepository<ContractGroup, Integer> {
Optional<ContractGroup> findByCode(String code);
Optional<ContractGroup> findFirstByNameContains(String name);
Optional<ContractGroup> findByName(String name);
}

View File

@@ -0,0 +1,17 @@
package com.ecep.contract.ds.contract.repository;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.stereotype.Repository;
import com.ecep.contract.model.ContractItem;
@Repository
public interface ContractItemRepository extends JpaRepository<ContractItem, Integer>, JpaSpecificationExecutor<ContractItem> {
List<ContractItem> findByContractId(int contractId);
List<ContractItem> findByInventoryId(int inventoryId);
}

View File

@@ -0,0 +1,15 @@
package com.ecep.contract.ds.contract.repository;
import java.util.Optional;
import org.springframework.stereotype.Repository;
import com.ecep.contract.ds.MyRepository;
import com.ecep.contract.model.ContractKind;
@Repository
public interface ContractKindRepository extends MyRepository<ContractKind, Integer> {
Optional<ContractKind> findByCode(String code);
Optional<ContractKind> findByName(String name);
}

View File

@@ -0,0 +1,18 @@
package com.ecep.contract.ds.contract.repository;
import java.util.List;
import org.springframework.stereotype.Repository;
import com.ecep.contract.ds.MyRepository;
import com.ecep.contract.model.Contract;
import com.ecep.contract.model.ContractPayPlan;
@Repository
public interface ContractPayPlanRepository extends MyRepository<ContractPayPlan, Integer> {
List<ContractPayPlan> findAllByContractId(Integer contractId);
List<ContractPayPlan> findAllByContract(Contract contract);
}

View File

@@ -0,0 +1,37 @@
package com.ecep.contract.ds.contract.repository;
import java.util.List;
import java.util.Optional;
import org.springframework.stereotype.Repository;
import com.ecep.contract.ContractPayWay;
import com.ecep.contract.ds.MyRepository;
import com.ecep.contract.model.Contract;
@Repository
public interface ContractRepository extends MyRepository<Contract, Integer> {
Optional<Contract> findByGuid(String guid);
Optional<Contract> findByProjectIdAndPayWay(int projectId, ContractPayWay payWay);
List<Contract> findAllByProjectIdAndPayWay(int projectId, ContractPayWay payWay);
Optional<Contract> findByCode(String code);
int deleteAllByCompanyId(int companyId);
List<Contract> findByCodeStartsWith(String code);
List<Contract> findByPayWayAndCodeStartsWith(ContractPayWay payWay, String code);
List<Contract> findAllByParentCode(String parentCode);
Optional<Contract> findFirstByName(String name);
List<Contract> findAllByCompanyId(int companyId);
List<Contract> findAllByProjectId(int projectId);
}

View File

@@ -0,0 +1,16 @@
package com.ecep.contract.ds.contract.repository;
import java.util.Optional;
import org.springframework.stereotype.Repository;
import com.ecep.contract.ds.MyRepository;
import com.ecep.contract.model.ContractType;
@Repository
public interface ContractTypeRepository extends MyRepository<ContractType, Integer> {
Optional<ContractType> findByCode(String code);
Optional<ContractType> findByName(String name);
}

View File

@@ -0,0 +1,17 @@
package com.ecep.contract.ds.contract.repository;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.stereotype.Repository;
import com.ecep.contract.model.ExtendVendorInfo;
@Repository
public interface ExtendVendorInfoRepository extends
// JPA interfaces
JpaRepository<ExtendVendorInfo, Integer>, JpaSpecificationExecutor<ExtendVendorInfo> {
Optional<ExtendVendorInfo> findByContractId(Integer contractId);
}

View File

@@ -0,0 +1,19 @@
package com.ecep.contract.ds.contract.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.stereotype.Repository;
import com.ecep.contract.model.PurchaseBillVoucherItem;
@Repository
public interface PurchaseBillVoucherItemRepository extends
// JDBC interfaces
CrudRepository<PurchaseBillVoucherItem, Integer>,
PagingAndSortingRepository<PurchaseBillVoucherItem, Integer>,
// JPA interfaces
JpaRepository<PurchaseBillVoucherItem, Integer>, JpaSpecificationExecutor<PurchaseBillVoucherItem> {
}

View File

@@ -0,0 +1,24 @@
package com.ecep.contract.ds.contract.repository;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.stereotype.Repository;
import com.ecep.contract.model.PurchaseBillVoucher;
@Repository
public interface PurchaseBillVoucherRepository extends
// JDBC interfaces
CrudRepository<PurchaseBillVoucher, Integer>, PagingAndSortingRepository<PurchaseBillVoucher, Integer>,
// JPA interfaces
JpaRepository<PurchaseBillVoucher, Integer>, JpaSpecificationExecutor<PurchaseBillVoucher> {
Optional<PurchaseBillVoucher> findByCode(String code);
Optional<PurchaseBillVoucher> findByRefId(Integer refId);
}

View File

@@ -0,0 +1,18 @@
package com.ecep.contract.ds.contract.repository;
import java.util.List;
import org.springframework.stereotype.Repository;
import com.ecep.contract.ds.MyRepository;
import com.ecep.contract.model.PurchaseOrder;
import com.ecep.contract.model.PurchaseOrderItem;
@Repository
public interface PurchaseOrderItemRepository extends MyRepository<PurchaseOrderItem, Integer>{
List<PurchaseOrderItem> findAllByRefId(int refId);
List<PurchaseOrderItem> findAllByOrder(PurchaseOrder order);
}

View File

@@ -0,0 +1,29 @@
package com.ecep.contract.ds.contract.repository;
import java.util.List;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.stereotype.Repository;
import com.ecep.contract.model.Contract;
import com.ecep.contract.model.PurchaseOrder;
@Repository
public interface PurchaseOrderRepository extends
// JDBC interfaces
CrudRepository<PurchaseOrder, Integer>, PagingAndSortingRepository<PurchaseOrder, Integer>,
// JPA interfaces
JpaRepository<PurchaseOrder, Integer>, JpaSpecificationExecutor<PurchaseOrder> {
Optional<PurchaseOrder> findByCode(String code);
Optional<PurchaseOrder> findByRefId(Integer refId);
List<PurchaseOrder> findAllByContract(Contract contract);
List<PurchaseOrder> findByCodeStartsWith(String code);
}

View File

@@ -0,0 +1,19 @@
package com.ecep.contract.ds.contract.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.stereotype.Repository;
import com.ecep.contract.model.SalesBillVoucherItem;
@Repository
public interface SalesBillVoucherItemRepository extends
// JDBC interfaces
CrudRepository<SalesBillVoucherItem, Integer>,
PagingAndSortingRepository<SalesBillVoucherItem, Integer>,
// JPA interfaces
JpaRepository<SalesBillVoucherItem, Integer>, JpaSpecificationExecutor<SalesBillVoucherItem> {
}

View File

@@ -0,0 +1,22 @@
package com.ecep.contract.ds.contract.repository;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.stereotype.Repository;
import com.ecep.contract.model.SalesBillVoucher;
@Repository
public interface SalesBillVoucherRepository extends
// JDBC interfaces
CrudRepository<SalesBillVoucher, Integer>, PagingAndSortingRepository<SalesBillVoucher, Integer>,
// JPA interfaces
JpaRepository<SalesBillVoucher, Integer>, JpaSpecificationExecutor<SalesBillVoucher> {
Optional<SalesBillVoucher> findByCode(String code);
}

View File

@@ -0,0 +1,27 @@
package com.ecep.contract.ds.contract.repository;
import java.util.List;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.stereotype.Repository;
import com.ecep.contract.model.SalesOrder;
import com.ecep.contract.model.SalesOrderItem;
@Repository
public interface SalesOrderItemRepository extends
// JDBC interfaces
CrudRepository<SalesOrderItem, Integer>, PagingAndSortingRepository<SalesOrderItem, Integer>,
// JPA interfaces
JpaRepository<SalesOrderItem, Integer>, JpaSpecificationExecutor<SalesOrderItem> {
Optional<SalesOrderItem> findByCode(String code);
List<SalesOrderItem> findAllByOrder(SalesOrder order);
List<SalesOrderItem> findByCodeStartsWith(String code);
}

View File

@@ -0,0 +1,27 @@
package com.ecep.contract.ds.contract.repository;
import java.util.List;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.stereotype.Repository;
import com.ecep.contract.model.Contract;
import com.ecep.contract.model.SalesOrder;
@Repository
public interface SalesOrderRepository extends
// JDBC interfaces
CrudRepository<SalesOrder, Integer>, PagingAndSortingRepository<SalesOrder, Integer>,
// JPA interfaces
JpaRepository<SalesOrder, Integer>, JpaSpecificationExecutor<SalesOrder> {
Optional<SalesOrder> findByCode(String code);
List<SalesOrder> findAllByContract(Contract contract);
List<SalesOrder> findByCodeStartsWith(String code);
}

View File

@@ -0,0 +1,81 @@
package com.ecep.contract.ds.contract.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import com.ecep.contract.IEntityService;
import com.ecep.contract.ds.contract.repository.ContractBidVendorRepository;
import com.ecep.contract.model.Company;
import com.ecep.contract.model.Contract;
import com.ecep.contract.model.ContractBidVendor;
@Lazy
@Service
@CacheConfig(cacheNames = "contract-ven-bid")
public class ContractBidVendorService implements IEntityService<ContractBidVendor> {
@Lazy
@Autowired
private ContractBidVendorRepository repository;
@Cacheable(key = "#p0")
public ContractBidVendor findById(Integer id) {
return repository.findById(id).orElse(null);
}
@Override
public Specification<ContractBidVendor> getSpecification(String searchText) {
return null;
}
@Override
public Page<ContractBidVendor> findAll(Specification<ContractBidVendor> spec, Pageable pageable) {
return repository.findAll(spec, pageable);
}
@Cacheable(key = "'allbycontract-'+#p0.id")
public List<ContractBidVendor> findByContract(Contract contract) {
return repository.findByContractId(contract.getId());
}
@Caching(evict = {
@CacheEvict(key = "#p0.id"),
@CacheEvict(key = "'allbycontract-'+#p0.contract.id")
})
public ContractBidVendor save(ContractBidVendor bidVendor) {
return repository.save(bidVendor);
}
@Caching(evict = {
@CacheEvict(key = "#p0.id"),
@CacheEvict(key = "'allbycontract-'+#p0.contract.id")
})
public void delete(ContractBidVendor bidVendor) {
repository.delete(bidVendor);
}
public List<ContractBidVendor> findAll(Specification<ContractBidVendor> spec, Sort sort) {
return repository.findAll(spec, sort);
}
@Caching(evict = {
@CacheEvict(key = "#p0.id")
})
public void deleteById(int id) {
repository.deleteById(id);
}
public List<ContractBidVendor> findByContractAndCompany(Contract contract, Company company) {
return repository.findByContractIdAndCompanyId(contract.getId(), company.getId());
}
}

View File

@@ -0,0 +1,66 @@
package com.ecep.contract.ds.contract.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import com.ecep.contract.ds.contract.repository.ContractCatalogRepository;
import com.ecep.contract.model.ContractCatalog;
/**
* 合同分类服务
*/
@Lazy
@Service
@CacheConfig(cacheNames = "contract-catalog")
public class ContractCatalogService {
@Lazy
@Autowired
private ContractCatalogRepository repository;
/**
* 根据 id 查找 ContractCatalog
*/
@Cacheable(key = "#p0")
public ContractCatalog findById(Integer id) {
return repository.findById(id).orElse(null);
}
public ContractCatalog findByName(String name) {
return repository.findByName(name).orElse(null);
}
@Cacheable(key = "'code-'+#p0")
public ContractCatalog findByCode(String code) {
return repository.findByCode(code).orElse(null);
}
@Cacheable(key = "'catalogs'")
public List<ContractCatalog> findAll() {
return repository.findAll();
}
@Caching(evict = {
@CacheEvict(key = "#p0.id"),
@CacheEvict(key = "'code-'+#p0.code"),
@CacheEvict(key = "'catalogs'"),
})
public ContractCatalog save(ContractCatalog catalog) {
return repository.save(catalog);
}
@Caching(evict = {
@CacheEvict(key = "#p0.id"),
@CacheEvict(key = "'code-'+#p0.code"),
@CacheEvict(key = "'catalogs'"),
})
public void delete(ContractCatalog catalog) {
repository.delete(catalog);
}
}

View File

@@ -0,0 +1,207 @@
package com.ecep.contract.ds.contract.service;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import com.ecep.contract.ContractFileType;
import com.ecep.contract.IEntityService;
import com.ecep.contract.ds.contract.repository.ContractFileRepository;
import com.ecep.contract.ds.contract.repository.ContractFileTypeLocalRepository;
import com.ecep.contract.model.Contract;
import com.ecep.contract.model.ContractFile;
import com.ecep.contract.model.ContractFileTypeLocal;
@Lazy
@Service
@CacheConfig(cacheNames = "contract-file")
public class ContractFileService implements IEntityService<ContractFile> {
private static final Logger logger = LoggerFactory.getLogger(ContractFileService.class);
/**
* 销售成本核算审批表模板
*/
public static final String KEY_CUSTOMER_COST_TEMPLATE = "customer.contract.cost.template";
/**
* 项目投标审批表模板
*/
public static final String KEY_CUSTOMER_BID_TEMPLATE = "customer.contract.bid.template";
/**
* 销售合同审批表模板
*/
public static final String KEY_CUSTOMER_APPLY_TEMPLATE = "customer.contract.apply.template";
/**
* 投标报价表模板
*/
public static final String KEY_QUOTATION_TEMPLATE = "customer.contract.quotation.template";
/**
* 采购合同审批表模板
*/
public static final String KEY_VENDOR_APPLY_TEMPLATE = "vendor.contract.apply.template";
@Lazy
@Autowired
private ContractFileRepository contractFileRepository;
@Lazy
@Autowired
private ContractFileTypeLocalRepository contractFileTypeLocalRepository;
@Cacheable(key = "#p0")
public ContractFile findById(Integer id) {
return contractFileRepository.findById(id).orElse(null);
}
@Override
public Specification<ContractFile> getSpecification(String searchText) {
if (!StringUtils.hasText(searchText)) {
return null;
}
return (root, query, builder) -> {
return builder.or(
builder.like(root.get("fileName"), "%" + searchText + "%"),
builder.like(root.get("description"), "%" + searchText + "%"));
};
}
@Override
public Page<ContractFile> findAll(Specification<ContractFile> spec, Pageable pageable) {
return contractFileRepository.findAll(spec, pageable);
}
public List<ContractFile> findAll(Specification<ContractFile> spec, Sort by) {
return contractFileRepository.findAll(spec, by);
}
public List<ContractFile> findAllByContractAndFileType(Contract contract, ContractFileType contractFileType) {
return contractFileRepository.findAllByContractAndType(contract, contractFileType);
}
/**
* 按销售逻辑处理
*/
@Deprecated
public void verifyAsCustomer(Contract contract, Consumer<String> status) {
// 检查 成本审批
if (!checkFileExist(contract, ContractFileType.CostForm)) {
status.accept("销售成本审批表未找到");
}
// 检查 合同审批表
if (!checkFileExist(contract, ContractFileType.ContractApprovalForm)) {
status.accept("销售合同审批表未找到");
}
// 检查 合同
if (!checkFileExist(contract, ContractFileType.Contract)) {
status.accept("销售合同未找到");
}
}
public boolean checkFileExist(Contract contract, ContractFileType type) {
List<ContractFile> files = contractFileRepository.findAllByContractAndType(contract, type);
if (files == null || files.isEmpty()) {
return false;
}
return true;
}
/**
* 按采购逻辑处理
*/
@Deprecated
public void verifyAsVendor(Contract contract, Consumer<String> status) {
// 检查 申请表
if (!checkFileExist(contract, ContractFileType.PurchaseRequestForm)) {
status.accept("采购申请表未找到");
}
// 检查 合同审批表
if (!checkFileExist(contract, ContractFileType.PurchaseContractApprovalForm)) {
status.accept("采购合同审批表未找到");
}
// 检查 合同
if (!checkFileExist(contract, ContractFileType.Contract)) {
status.accept("采购合同未找到");
}
// 检查 提货单
// contractFileRepository.findAllByContractAndType(contract,
// ContractFileType.DeliveryOrder);
}
@Caching(evict = {
@CacheEvict(key = "#p0.id"),
@CacheEvict(key = "'allbycontract-'+#p0.contract.id")
})
public void delete(ContractFile file) {
contractFileRepository.deleteById(file.getId());
}
@Caching(evict = {
@CacheEvict(key = "#p0.id"),
@CacheEvict(key = "'allbycontract-'+#p0.contract.id")
})
public ContractFile save(ContractFile contractFile) {
return contractFileRepository.save(contractFile);
}
public void deleteById(int id) {
contractFileRepository.deleteById(id);
}
@Cacheable(key = "'allbycontract-'+#p0.id")
public List<ContractFile> findAllByContract(Contract contract) {
return contractFileRepository.findAllByContract(contract);
}
public List<ContractFile> searchByContract(Contract contract, String userText) {
Specification<ContractFile> spec = (root, query, builder) -> {
return builder.and(
builder.equal(root.get("contract"), contract),
builder.or(
builder.like(root.get("fileName"), "%" + userText + "%"),
builder.like(root.get("description"), "%" + userText + "%")));
};
return contractFileRepository.findAll(spec);
}
// @Cacheable(key = "'type-locals-'+#p0")
// public List<ContractFileTypeLocal> findAllFileTypes(String lang) {
// Map<ContractFileType, ContractFileTypeLocal> map =
// contractFileTypeLocalRepository.getCompleteMapByLocal(lang);
// List<ContractFileTypeLocal> list = new ArrayList<>(map.values());
// list.sort((o1, o2) -> Objects.compare(o1.getValue(), o2.getValue(),
// String::compareTo));
// return list;
// }
@Cacheable(key = "'type-locals-'+#p0")
public Map<ContractFileType, ContractFileTypeLocal> findAllFileTypes(String lang) {
return contractFileTypeLocalRepository.getCompleteMapByLocal(lang);
}
@Caching(evict = {
@CacheEvict(key = "'type-locals-'+#p0.lang"),
@CacheEvict(key = "'type-'+#p0.type+'-local-'+#p0.lang"),
})
public ContractFileTypeLocal save(ContractFileTypeLocal type) {
return contractFileTypeLocalRepository.save(type);
}
@Cacheable(key = "'type-'+#p0+'-local-'+#p1")
public ContractFileTypeLocal findFileTypeLocalByTypeAndLang(ContractFileType type, String lang) {
return contractFileTypeLocalRepository.getCompleteByTypeAndLang(type, lang);
}
}

View File

@@ -0,0 +1,103 @@
package com.ecep.contract.ds.contract.service;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import com.ecep.contract.IEntityService;
import com.ecep.contract.ds.contract.repository.ContractGroupRepository;
import com.ecep.contract.model.ContractGroup;
/**
* 合同分组服务
*/
@Lazy
@Service
@CacheConfig(cacheNames = "contract-group")
public class ContractGroupService implements IEntityService<ContractGroup> {
private static final Logger logger = LoggerFactory.getLogger(ContractGroupService.class);
@Lazy
@Autowired
private ContractGroupRepository repository;
@Cacheable(key = "#p0")
public ContractGroup findById(Integer id) {
return repository.findById(id).orElse(null);
}
@Override
public Page<ContractGroup> findAll(Specification<ContractGroup> spec, Pageable pageable) {
return repository.findAll(spec, pageable);
}
@Override
public Specification<ContractGroup> getSpecification(String searchText) {
return (root, query, builder)->{
return builder.or(
builder.like(root.get("code"), "%" + searchText + "%"),
builder.like(root.get("name"), "%" + searchText + "%"),
builder.like(root.get("title"), "%" + searchText + "%")
);
};
}
public ContractGroup findByName(String name) {
return repository.findByName(name).orElse(null);
}
@Cacheable(key = "'code-'+#p0")
public ContractGroup findByCode(String code) {
return repository.findByCode(code).orElse(null);
}
@Cacheable(key = "'groups'")
public List<ContractGroup> findAll() {
return repository.findAll();
}
@Caching(evict = {
@CacheEvict(key = "'groups'"),
@CacheEvict(key = "#p0.id"),
@CacheEvict(key = "'code-'+#p0.code"),
})
public ContractGroup save(ContractGroup group) {
return repository.save(group);
}
@Caching(evict = {
@CacheEvict(key = "#p0"),
@CacheEvict(key = "'groups'"),
})
public void delete(Integer id) {
repository.deleteById(id);
}
@Caching(evict = {
@CacheEvict(key = "#p0"),
@CacheEvict(key = "'groups'"),
@CacheEvict(key = "'code-'+#p0.code"),
})
public void delete(ContractGroup group) {
repository.delete(group);
}
public ContractGroup newContractGroup() {
ContractGroup group = new ContractGroup();
group.setCode("");
group.setName("");
group.setTitle("");
return group;
}
}

View File

@@ -0,0 +1,95 @@
package com.ecep.contract.ds.contract.service;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import com.ecep.contract.IEntityService;
import com.ecep.contract.ds.contract.repository.ContractItemRepository;
import com.ecep.contract.model.Contract;
import com.ecep.contract.model.ContractItem;
import com.ecep.contract.model.Inventory;
import jakarta.persistence.criteria.Path;
@Lazy
@Service
@CacheConfig(cacheNames = "contract-item")
public class ContractItemService implements IEntityService<ContractItem> {
private static final Logger logger = LoggerFactory.getLogger(ContractItemService.class);
@Lazy
@Autowired
private ContractItemRepository itemRepository;
@Cacheable(key = "#p0")
public ContractItem findById(Integer id) {
return itemRepository.findById(id).orElse(null);
}
@Override
public Specification<ContractItem> getSpecification(String searchText) {
if (!StringUtils.hasText(searchText)) {
return null;
}
return (root, query, builder) -> {
Path<Inventory> inventory = root.get("inventory");
return builder.or(
builder.like(root.get("itemCode"), "%" + searchText + "%"),
builder.like(root.get("title"), "%" + searchText + "%"),
builder.like(root.get("specification"), "%" + searchText + "%"),
builder.like(root.get("unit"), "%" + searchText + "%"),
builder.like(root.get("remark"), "%" + searchText + "%"),
builder.and(
inventory.isNotNull(), builder.or(
builder.like(inventory.get("name"), "%" + searchText + "%"),
builder.like(inventory.get("code"), "%" + searchText + "%"),
builder.like(inventory.get("specification"), "%" + searchText + "%"))));
};
}
@Override
public Page<ContractItem> findAll(Specification<ContractItem> spec, Pageable pageable) {
return itemRepository.findAll(spec, pageable);
}
public List<ContractItem> findAllByContract(Contract contract) {
return itemRepository.findByContractId(contract.getId());
}
public List<ContractItem> findAllByInventory(Inventory inventory) {
return itemRepository.findByInventoryId(inventory.getId());
}
public List<ContractItem> findAll(Specification<ContractItem> spec, Sort sort) {
return itemRepository.findAll(spec, sort);
}
@Caching(evict = {
@CacheEvict(key = "#p0.id")
})
public ContractItem save(ContractItem item) {
return itemRepository.save(item);
}
@Caching(evict = {
@CacheEvict(key = "#p0.id")
})
public void delete(ContractItem item) {
itemRepository.delete(item);
}
}

View File

@@ -0,0 +1,95 @@
package com.ecep.contract.ds.contract.service;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import com.ecep.contract.IEntityService;
import com.ecep.contract.ds.contract.repository.ContractKindRepository;
import com.ecep.contract.model.ContractKind;
/**
* 合同种类服务
*/
@Lazy
@Service
@CacheConfig(cacheNames = "contract-kind")
public class ContractKindService implements IEntityService<ContractKind> {
private static final Logger logger = LoggerFactory.getLogger(ContractKindService.class);
@Lazy
@Autowired
private ContractKindRepository repository;
@Cacheable(key = "'kind-'+#p0")
public ContractKind findById(Integer id) {
return repository.findById(id).orElse(null);
}
@Override
public Page<ContractKind> findAll(Specification<ContractKind> spec, Pageable pageable) {
return repository.findAll(spec, pageable);
}
@Override
public Specification<ContractKind> getSpecification(String searchText) {
return (root, query, builder) -> {
return builder.or(
builder.like(root.get("code"), "%" + searchText + "%"),
builder.like(root.get("name"), "%" + searchText + "%"),
builder.like(root.get("title"), "%" + searchText + "%")
);
};
}
@Override
public void delete(ContractKind entity) {
repository.delete(entity);
}
public ContractKind findByName(String name) {
return repository.findByName(name).orElse(null);
}
@Cacheable(key = "'code-'+#p0")
public ContractKind findByCode(String code) {
return repository.findByCode(code).orElse(null);
}
@Cacheable(key = "'kinds'")
public List<ContractKind> findAll() {
return repository.findAll();
}
@Caching(
evict = {
@CacheEvict(key = "'kinds'"),
@CacheEvict(key = "'kind-'+#p0.id"),
@CacheEvict(key = "'code-'+#p0.name"),
}
)
public ContractKind save(ContractKind kind) {
return repository.save(kind);
}
@Caching(
evict = {
@CacheEvict(key = "'kinds'"),
@CacheEvict(key = "'kind-'+#p0"),
}
)
public void delete(Integer id) {
repository.deleteById(id);
}
}

View File

@@ -0,0 +1,79 @@
package com.ecep.contract.ds.contract.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import com.ecep.contract.IEntityService;
import com.ecep.contract.ds.contract.repository.ContractPayPlanRepository;
import com.ecep.contract.model.Contract;
import com.ecep.contract.model.ContractPayPlan;
/**
* 合同支付计划服务
*/
@Lazy
@Service
@CacheConfig(cacheNames = "contract-pay-plan")
public class ContractPayPlanService implements IEntityService<ContractPayPlan> {
@Lazy
@Autowired
private ContractPayPlanRepository repository;
@Cacheable(key = "#p0")
@Override
public ContractPayPlan findById(Integer id) {
return repository.findById(id).orElse(null);
}
@Override
public Specification<ContractPayPlan> getSpecification(String searchText) {
if (!StringUtils.hasText(searchText)) {
return null;
}
return (root, query, cb) -> {
return cb.or(cb.like(root.get("payTerm"), "%" + searchText + "%"));
};
}
@Override
public Page<ContractPayPlan> findAll(Specification<ContractPayPlan> spec, Pageable pageable) {
return repository.findAll(spec, pageable);
}
public List<ContractPayPlan> findAllByContract(Contract contract) {
return repository.findAllByContract(contract);
}
@Caching(
evict = {
@CacheEvict(key = "#p0.id")
}
)
@Override
public void delete(ContractPayPlan entity) {
repository.delete(entity);
}
@Caching(
evict = {
@CacheEvict(key = "#p0.id")
}
)
@Override
public ContractPayPlan save(ContractPayPlan entity) {
return repository.save(entity);
}
}

View File

@@ -0,0 +1,412 @@
package com.ecep.contract.ds.contract.service;
import java.io.File;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import com.ecep.contract.ContractPayWay;
import com.ecep.contract.IEntityService;
import com.ecep.contract.ds.contract.repository.ContractRepository;
import com.ecep.contract.ds.other.service.SysConfService;
import com.ecep.contract.model.Company;
import com.ecep.contract.model.CompanyCustomer;
import com.ecep.contract.model.CompanyVendor;
import com.ecep.contract.model.Contract;
import com.ecep.contract.model.ContractCatalog;
import com.ecep.contract.model.ContractGroup;
import com.ecep.contract.model.ContractKind;
import com.ecep.contract.model.ContractType;
import com.ecep.contract.model.Project;
import com.ecep.contract.util.MyStringUtils;
import com.ecep.contract.util.SpecificationUtils;
import jakarta.persistence.criteria.Predicate;
/**
* 合同服务类
* 继承基础服务并实现视图模型接口
*/
@Lazy
@Service
@CacheConfig(cacheNames = "contract")
public class ContractService implements IEntityService<Contract> {
private static final Logger logger = LoggerFactory.getLogger(ContractService.class);
public static final String CONTRACT_BASE_PATH = "contract.base.path";
@Lazy
@Autowired
private ContractCatalogService contractCatalogService;
@Lazy
@Autowired
private ContractTypeService contractTypeService;
@Lazy
@Autowired
private ContractGroupService contractGroupService;
@Lazy
@Autowired
private ContractKindService contractKindService;
@Lazy
@Autowired
private ContractFileService contractFileService;
@Lazy
@Autowired
protected ContractRepository contractRepository;
@Lazy
@Autowired
protected SysConfService confService;
@Cacheable(key = "#p0")
public Contract findById(Integer id) {
return contractRepository.findById(id).orElse(null);
}
public Contract findByName(String name) {
return contractRepository.findFirstByName(name).orElse(null);
}
@Cacheable(key = "'code-'+#p0")
public Contract findByCode(String code) {
return contractRepository.findByCode(code).orElse(null);
}
public Contract findByGuid(String guid) {
return contractRepository.findByGuid(guid).orElse(null);
}
/**
* 保存实体对象,异步方法
*/
@Caching(evict = {
@CacheEvict(key = "#p0.id"),
@CacheEvict(key = "'code-'+#p0.code")
})
public Contract save(Contract contract) {
return contractRepository.save(contract);
}
@Caching(evict = {
@CacheEvict(key = "#p0.id"),
@CacheEvict(key = "'code-'+#p0.code")
})
public void delete(Contract contract) {
contractRepository.delete(contract);
}
public long count() {
return contractRepository.count();
}
public long count(Specification<Contract> spec) {
return contractRepository.count(spec);
}
public Page<Contract> findAll(Specification<Contract> spec, Pageable pageable) {
return contractRepository.findAll(spec, pageable);
}
public List<Contract> findAll(Specification<Contract> spec, Sort sort) {
return contractRepository.findAll(spec, sort);
}
public List<Contract> findAllByCompany(Company company) {
return contractRepository.findAllByCompanyId(company.getId());
}
public List<Contract> findAllByProject(Project project) {
return contractRepository.findAllByProjectId(project.getId());
}
public List<Contract> findAllSalesByProject(Project project) {
return contractRepository.findAllByProjectIdAndPayWay(project.getId(), ContractPayWay.RECEIVE);
}
public Contract findSalesByProject(Project project) {
return contractRepository.findByProjectIdAndPayWay(project.getId(), ContractPayWay.RECEIVE).orElse(null);
}
public File getBasePath() {
return new File(confService.getString(CONTRACT_BASE_PATH));
}
public ContractGroup findGroupById(Integer id) {
return contractGroupService.findById(id);
}
public ContractGroup findGroupByCode(String groupCode) {
return contractGroupService.findByCode(groupCode);
}
public List<ContractGroup> findAllGroups() {
return contractGroupService.findAll();
}
public ContractType findTypeById(Integer id) {
return contractTypeService.findById(id);
}
public ContractType findTypeByCode(String typeCode) {
return contractTypeService.findByCode(typeCode);
}
public ContractKind findKindById(Integer id) {
return contractKindService.findById(id);
}
public ContractKind findKindByName(String kindName) {
return contractKindService.findByName(kindName);
}
/**
* 返回合同的分类目录
*/
public File getContractCatalogPath(ContractCatalog catalog, Contract contract) {
String parent = catalog.getParent();
File dir = getBasePath();
if (StringUtils.hasText(parent)) {
dir = new File(dir, parent);
if (!dir.exists()) {
if (!dir.mkdir()) {
System.out.println("unable make directory = " + dir.getAbsolutePath());
return null;
}
}
}
dir = new File(dir, catalog.getPath());
if (!dir.exists()) {
if (!dir.mkdir()) {
System.out.println("unable make directory = " + dir.getAbsolutePath());
return null;
}
}
if (catalog.isUseYear()) {
String code = contract.getCode();
String catalogCode = catalog.getCode();
int length = catalogCode.length();
String yearCode = code.substring(length, length + 2);
dir = new File(dir, "20" + yearCode);
if (!dir.exists()) {
if (!dir.mkdir()) {
System.out.println("unable make directory = " + dir.getAbsolutePath());
return null;
}
}
}
return dir;
}
/**
* 查找合同的分类
*/
public ContractCatalog findContractCatalogByContract(Contract contract) {
String code = contract.getCode();
String catalogCode = null;
// 第二个字符是数字时,快速处理
if (Character.isDigit(code.charAt(1))) {
// 只有一个字母表示合同类型
catalogCode = code.substring(0, 1);
} else {
// 使用正则找出 合同类型
String regex = "^([A-Z]{1,4})(\\d{4,5})";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(code);
if (matcher.find()) {
catalogCode = matcher.group(1);
System.out.println("字母部分: " + matcher.group(1));
System.out.println("数字部分: " + matcher.group(2));
}
if (catalogCode == null) {
if (logger.isInfoEnabled()) {
logger.info("contract {} can't find catalog code", code);
}
return null;
}
}
return contractCatalogService.findByCode(catalogCode);
}
public Contract createNew() {
Contract contract = new Contract();
contract.setCreated(LocalDateTime.now());
return contract;
}
@Override
public Specification<Contract> getSpecification(String searchText) {
if (!StringUtils.hasText(searchText)) {
return null;
}
return SpecificationUtils.andWith(searchText, this::buildSearchSpecification);
}
/**
* 构建搜索规范
*/
protected Specification<Contract> buildSearchSpecification(String searchText) {
return (root, query, builder) -> {
return builder.or(
builder.like(root.get("name"), "%" + searchText + "%"),
builder.like(root.get("code"), "%" + searchText + "%"),
builder.like(root.get("parentCode"), "%" + searchText + "%"),
builder.like(root.get("description"), "%" + searchText + "%"),
builder.like(root.get("guid"), "%" + searchText + "%"));
};
}
public List<Contract> findAllByCompanyVendor(CompanyVendor vendor, LocalDate beginDate, LocalDate endDate) {
Company company = vendor.getCompany();
return contractRepository.findAll((root, query, cb) -> {
Predicate p = cb.and(
cb.equal(root.get("company").get("id"), company.getId()),
cb.equal(root.get("payWay"), ContractPayWay.PAY));
return applyPredicate(root, cb, p, beginDate, endDate);
}, Sort.unsorted());
}
public List<Contract> findAllByCompanyCustomer(CompanyCustomer customer, LocalDate beginDate, LocalDate endDate) {
Company company = customer.getCompany();
return contractRepository.findAll((root, query, cb) -> {
Predicate p = cb.and(
cb.equal(root.get("company"), company),
cb.equal(root.get("payWay"), ContractPayWay.RECEIVE));
return applyPredicate(root, cb, p, beginDate, endDate);
}, Sort.unsorted());
}
private Predicate applyPredicate(
jakarta.persistence.criteria.Root<Contract> root,
jakarta.persistence.criteria.CriteriaBuilder cb,
Predicate base, LocalDate beginDate, LocalDate endDate) {
if (beginDate == null && endDate == null) {
return base;
} else if (endDate == null) {
return cb.and(base, cb.greaterThanOrEqualTo(root.get("setupDate"), beginDate));
} else if (beginDate == null) {
return cb.and(base, cb.lessThanOrEqualTo(root.get("setupDate"), endDate));
} else {
return cb.and(base, cb.between(root.get("setupDate"), beginDate, endDate));
}
}
/**
* 判断是否是非子合同编号
*/
public boolean isSubContractCode(String code) {
if (!StringUtils.hasText(code)) {
return false;
}
return code.contains("-");
}
public boolean isSubContract(Contract contract) {
return isSubContractCode(contract.getCode());
}
public String getParentCode(Contract contract) {
String code = contract.getCode();
int index = code.indexOf("-");
if (index != -1) {
return code.substring(0, index);
}
return null;
}
/**
* 更新合同的主合同编号(从当前合同的额合同编码上推测)
*/
public boolean updateParentCode(Contract contract) {
if (!isSubContract(contract)) {
return false;
}
String parentCode = getParentCode(contract);
// fixed
if (Objects.equals(contract.getParentCode(), parentCode)) {
// 已经相同,跳过
return false;
}
Contract parentContract = null;
List<Contract> list = contractRepository.findByCodeStartsWith(parentCode);
if (list.isEmpty()) {
throw new NoSuchElementException("没有找到以" + parentCode + "开头的合同");
}
for (Contract c : list) {
if (!c.getCode().contains("-")) {
parentContract = c;
break;
}
}
if (parentContract == null) {
throw new NoSuchElementException("没有匹配到以" + parentCode + "开头的合同");
}
if (Objects.equals(contract.getParentCode(), parentContract.getCode())) {
return false;
}
contract.setParentCode(parentContract.getCode());
return true;
}
/**
* 删除 company 的 合同
*/
public void deleteByCompany(Company company) {
int deleted = contractRepository.deleteAllByCompanyId(company.getId());
if (deleted > 0) {
if (logger.isInfoEnabled()) {
logger.info("Delete {} records by company:#{}", deleted, company.getId());
}
}
}
/**
* 重置合同关联企业
*/
public void resetTo(Company from, Company to) {
List<Contract> list = contractRepository.findAllByCompanyId(from.getId());
if (list.isEmpty()) {
return;
}
for (Contract contract : list) {
contract.setDescription(MyStringUtils.appendIfAbsent(contract.getDescription(), "转自 " + from.getId()));
contract.setCompany(to);
}
contractRepository.saveAll(list);
}
public List<Contract> findAllByParent(Contract contract) {
return contractRepository.findAllByParentCode(contract.getCode());
}
public List<Contract> search(String searchText) {
Specification<Contract> spec = getSpecification(searchText);
return contractRepository.findAll(spec, Pageable.ofSize(10)).getContent();
}
public List<Contract> findByCodeStartsWith(ContractPayWay payWay, String parentCode) {
return contractRepository.findByPayWayAndCodeStartsWith(payWay, parentCode);
}
}

View File

@@ -0,0 +1,93 @@
package com.ecep.contract.ds.contract.service;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import com.ecep.contract.IEntityService;
import com.ecep.contract.ds.contract.repository.ContractTypeRepository;
import com.ecep.contract.model.ContractType;
/**
* 合同类型服务
*/
@Lazy
@Service
@CacheConfig(cacheNames = "contract-type")
public class ContractTypeService implements IEntityService<ContractType> {
private static final Logger logger = LoggerFactory.getLogger(ContractTypeService.class);
@Lazy
@Autowired
private ContractTypeRepository repository;
@Cacheable(key = "#p0")
public ContractType findById(Integer id) {
return repository.findById(id).orElse(null);
}
@Override
public Page<ContractType> findAll(Specification<ContractType> spec, Pageable pageable) {
return repository.findAll(spec, pageable);
}
public ContractType findByName(String name) {
return repository.findByName(name).orElse(null);
}
@Cacheable(key = "'code-'+#p0")
public ContractType findByCode(String code) {
return repository.findByCode(code).orElse(null);
}
@Cacheable(key = "'types'")
public List<ContractType> findAll() {
return repository.findAll();
}
@Caching(evict = {
@CacheEvict(key = "#p0.id"),
@CacheEvict(key = "'code-'+#p0.code"),
@CacheEvict(key = "'types'"),
})
public ContractType save(ContractType type) {
return repository.save(type);
}
@Caching(evict = {
@CacheEvict(key = "#p0"),
@CacheEvict(key = "'types'"),
})
public void delete(Integer id) {
repository.deleteById(id);
}
@Caching(evict = {
@CacheEvict(key = "#p0.id"),
@CacheEvict(key = "'code-'+#p0.code"),
@CacheEvict(key = "'types'"),
})
public void delete(ContractType type) {
repository.delete(type);
}
@Override
public Specification<ContractType> getSpecification(String searchText) {
return (root, query, builder) -> {
return builder.or(
builder.like(root.get("code"), "%" + searchText + "%"),
builder.like(root.get("name"), "%" + searchText + "%"));
};
}
}

View File

@@ -0,0 +1,85 @@
package com.ecep.contract.ds.contract.service;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import com.ecep.contract.ds.contract.repository.ExtendVendorInfoRepository;
import com.ecep.contract.ds.vendor.service.VendorGroupService;
import com.ecep.contract.model.Contract;
import com.ecep.contract.model.ExtendVendorInfo;
@Lazy
@Service
@CacheConfig(cacheNames = "contract-ext-ven-info")
public class ExtendVendorInfoService {
@Lazy
@Autowired
private ExtendVendorInfoRepository repository;
@Lazy
@Autowired
private VendorGroupService vendorGroupService;
@Cacheable(key = "#p0")
public ExtendVendorInfo findById(int id) {
return repository.findById(id).orElse(null);
}
@Cacheable(key = "'bycontract-'+#p0.id")
public ExtendVendorInfo findByContract(Contract contract) {
return repository.findByContractId(contract.getId()).orElse(null);
}
@Caching(evict = {
@CacheEvict(key = "#p0.id"),
@CacheEvict(key = "'bycontract-'+#p0.contract.id")
})
public ExtendVendorInfo save(ExtendVendorInfo bidVendor) {
return repository.save(bidVendor);
}
@Caching(evict = {
@CacheEvict(key = "#p0.id"),
@CacheEvict(key = "'bycontract-'+#p0.contract.id")
})
public void delete(ExtendVendorInfo bidVendor) {
repository.delete(bidVendor);
}
public List<ExtendVendorInfo> findAll(Specification<ExtendVendorInfo> spec, Sort sort) {
return repository.findAll(spec, sort);
}
public void deleteById(int id) {
repository.deleteById(id);
}
public ExtendVendorInfo newInstanceByContract(Contract contract) {
ExtendVendorInfo info = new ExtendVendorInfo();
info.setContract(contract);
if (StringUtils.hasText(contract.getCode())) {
String regex = "-([A-Z]{1,4})(\\d{1,4})";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(contract.getCode());
if (matcher.find()) {
info.setGroup(vendorGroupService.findByCode(matcher.group(1)));
info.setCodeSequenceNumber(Integer.parseInt(matcher.group(2)));
}
}
info.setAssignedProvider(false);
info.setPrePurchase(false);
return info;
}
}

View File

@@ -0,0 +1,69 @@
package com.ecep.contract.ds.contract.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import com.ecep.contract.IEntityService;
import com.ecep.contract.ds.contract.repository.PurchaseBillVoucherItemRepository;
import com.ecep.contract.model.PurchaseBillVoucherItem;
@Lazy
@Service
@CacheConfig(cacheNames = "purchase-bill-voucher-item")
public class PurchaseBillVoucherItemService implements IEntityService<PurchaseBillVoucherItem> {
@Lazy
@Autowired
private PurchaseBillVoucherItemRepository repository;
@Cacheable(key = "#p0")
@Override
public PurchaseBillVoucherItem findById(Integer id) {
return repository.findById(id).orElse(null);
}
@Override
public Specification<PurchaseBillVoucherItem> getSpecification(String searchText) {
return (root, query, builder) -> {
return builder.or(
builder.like(root.get("description"), "%" + searchText + "%"));
};
}
@Override
public Page<PurchaseBillVoucherItem> findAll(Specification<PurchaseBillVoucherItem> spec, Pageable pageable) {
return repository.findAll(spec, pageable);
}
@Caching(evict = {
@CacheEvict(key = "#p0.id"),
@CacheEvict(key = "'refId-'+#p0.refId")
})
@Override
public void delete(PurchaseBillVoucherItem entity) {
repository.delete(entity);
}
@Caching(evict = {
@CacheEvict(key = "#p0.id"),
@CacheEvict(key = "'refId-'+#p0.refId")
})
@Override
public PurchaseBillVoucherItem save(PurchaseBillVoucherItem entity) {
return repository.save(entity);
}
public List<PurchaseBillVoucherItem> findAll(Specification<PurchaseBillVoucherItem> spec, Sort sort) {
return repository.findAll(spec, sort);
}
}

View File

@@ -0,0 +1,115 @@
package com.ecep.contract.ds.contract.service;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import com.ecep.contract.IEntityService;
import com.ecep.contract.ds.contract.repository.PurchaseBillVoucherRepository;
import com.ecep.contract.model.PurchaseBillVoucher;
/**
* 采购账单凭证服务
*/
@Lazy
@Service
@CacheConfig(cacheNames = "purchase-bill-voucher")
public class PurchaseBillVoucherService implements IEntityService<PurchaseBillVoucher> {
private static final Logger logger = LoggerFactory.getLogger(PurchaseBillVoucherService.class);
@Lazy
@Autowired
private PurchaseBillVoucherRepository repository;
@Cacheable(key = "#p0")
public PurchaseBillVoucher findById(Integer id) {
return repository.findById(id).orElse(null);
}
@Override
public Specification<PurchaseBillVoucher> getSpecification(String searchText) {
// if null
if (!StringUtils.hasText(searchText)) {
return null;
}
return (root, query, builder) -> {
return builder.or(
builder.like(root.get("code"), "%" + searchText + "%"),
builder.like(root.get("description"), "%" + searchText + "%")
);
};
}
@Cacheable(key = "'code-'+#p0")
public PurchaseBillVoucher findByCode(String code) {
return repository.findByCode(code).orElse(null);
}
@Cacheable(key = "'refId-'+#p0")
public PurchaseBillVoucher findByRefId(Integer refId) {
return repository.findByRefId(refId).orElse(null);
}
/**
* 保存实体对象,异步方法
*
* @param voucher 要保存的实体对象
* @return 返回异步调用
*/
@Caching(
evict = {
@CacheEvict(key = "#p0.id"),
@CacheEvict(key = "'code-'+#p0.code"),
@CacheEvict(key = "'refId-'+#p0.refId")
}
)
public PurchaseBillVoucher save(PurchaseBillVoucher voucher) {
return repository.save(voucher);
}
@Caching(
evict = {
@CacheEvict(key = "#p0.id"),
@CacheEvict(key = "'code-'+#p0.code"),
@CacheEvict(key = "'refId-'+#p0.refId")
}
)
public void delete(PurchaseBillVoucher order) {
repository.delete(order);
}
public long count() {
return repository.count();
}
public long count(Specification<PurchaseBillVoucher> spec) {
return repository.count(spec);
}
public Page<PurchaseBillVoucher> findAll(Specification<PurchaseBillVoucher> spec, Pageable pageable) {
return repository.findAll(spec, pageable);
}
public List<PurchaseBillVoucher> findAll(Specification<PurchaseBillVoucher> spec, Sort sort) {
return repository.findAll(spec, sort);
}
public List<PurchaseBillVoucher> search(String searchText) {
return repository.findAll(getSpecification(searchText), Pageable.ofSize(10)).getContent();
}
}

View File

@@ -0,0 +1,95 @@
package com.ecep.contract.ds.contract.service;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import com.ecep.contract.IEntityService;
import com.ecep.contract.ds.contract.repository.PurchaseOrderItemRepository;
import com.ecep.contract.model.PurchaseOrderItem;
@Lazy
@Service
@CacheConfig(cacheNames = "contract-purchase-order-item")
public class PurchaseOrderItemService implements IEntityService<PurchaseOrderItem> {
private static final Logger logger = LoggerFactory.getLogger(PurchaseOrderItemService.class);
@Lazy
@Autowired
private PurchaseOrderItemRepository repository;
@Cacheable(key = "#p0")
@Override
public PurchaseOrderItem findById(Integer id) {
return repository.findById(id).orElse(null);
}
@Cacheable(key = "'refId-'+#p0")
public PurchaseOrderItem findByRefId(Integer itemRefId) {
List<PurchaseOrderItem> list = repository.findAllByRefId(itemRefId);
if (list.isEmpty()) {
return null;
}
while (list.size() > 1) {
PurchaseOrderItem item = list.removeLast();
repository.delete(item);
if (logger.isInfoEnabled()) {
logger.info("Duplicate PurchaseOrderItem, Delete {}", item);
}
}
return list.getFirst();
}
@Override
public Specification<PurchaseOrderItem> getSpecification(String searchText) {
if (!StringUtils.hasText(searchText)) {
return null;
}
return (root, query, builder) -> {
return builder.or(builder.like(root.get("description"), "%" + searchText + "%"));
};
}
@Override
public Page<PurchaseOrderItem> findAll(Specification<PurchaseOrderItem> spec, Pageable pageable) {
return repository.findAll(spec, pageable);
}
@Caching(
evict = {
@CacheEvict(key = "#p0.id"),
@CacheEvict(key = "'refId-'+#p0.refId")
}
)
@Override
public void delete(PurchaseOrderItem entity) {
repository.delete(entity);
}
@Caching(
evict = {
@CacheEvict(key = "#p0.id"), @CacheEvict(key = "'refId-'+#p0.refId")
}
)
@Override
public PurchaseOrderItem save(PurchaseOrderItem entity) {
return repository.save(entity);
}
public List<PurchaseOrderItem> findAll(Specification<PurchaseOrderItem> spec, Sort sort) {
return repository.findAll(spec, sort);
}
}

View File

@@ -0,0 +1,120 @@
package com.ecep.contract.ds.contract.service;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import com.ecep.contract.IEntityService;
import com.ecep.contract.ds.contract.repository.PurchaseOrderRepository;
import com.ecep.contract.model.Contract;
import com.ecep.contract.model.PurchaseOrder;
/**
* 采购订单服务
*/
@Lazy
@Service
@CacheConfig(cacheNames = "contract-purchase-order")
public class PurchaseOrdersService implements IEntityService<PurchaseOrder> {
private static final Logger logger = LoggerFactory.getLogger(PurchaseOrdersService.class);
@Lazy
@Autowired
private PurchaseOrderRepository purchaseOrderRepository;
@Cacheable(key = "#p0")
public PurchaseOrder findById(Integer id) {
return purchaseOrderRepository.findById(id).orElse(null);
}
@Override
public Specification<PurchaseOrder> getSpecification(String searchText) {
return (root, query, builder) -> {
return builder.or(
builder.like(root.get("code"), "%" + searchText + "%"),
builder.like(root.get("description"), "%" + searchText + "%")
);
};
}
@Cacheable(key = "'code-'+#p0")
public PurchaseOrder findByCode(String code) {
return purchaseOrderRepository.findByCode(code).orElse(null);
}
@Cacheable(key = "'refId-'+#p0")
public PurchaseOrder findByRefId(Integer refId) {
return purchaseOrderRepository.findByRefId(refId).orElse(null);
}
/**
* 保存实体对象,异步方法
*
* @param order 要保存的实体对象
* @return 返回异步调用
*/
@Caching(
evict = {
@CacheEvict(key = "#p0.id"),
@CacheEvict(key = "'code-'+#p0.code"),
@CacheEvict(key = "'refId-'+#p0.refId")
}
)
public PurchaseOrder save(PurchaseOrder order) {
return purchaseOrderRepository.save(order);
}
@Caching(
evict = {
@CacheEvict(key = "#p0.id"),
@CacheEvict(key = "'code-'+#p0.code"),
@CacheEvict(key = "'refId-'+#p0.refId")
}
)
public void delete(PurchaseOrder order) {
purchaseOrderRepository.delete(order);
}
public long count() {
return purchaseOrderRepository.count();
}
public long count(Specification<PurchaseOrder> spec) {
return purchaseOrderRepository.count(spec);
}
public Page<PurchaseOrder> findAll(Specification<PurchaseOrder> spec, Pageable pageable) {
return purchaseOrderRepository.findAll(spec, pageable);
}
public List<PurchaseOrder> findAll(Specification<PurchaseOrder> spec, Sort sort) {
return purchaseOrderRepository.findAll(spec, sort);
}
public List<PurchaseOrder> findAllByContract(Contract contract) {
return purchaseOrderRepository.findAllByContract(contract);
}
public List<PurchaseOrder> search(String searchText) {
Specification<PurchaseOrder> spec = (root, query, builder) -> {
return builder.or(
builder.like(root.get("name"), "%" + searchText + "%"),
builder.like(root.get("code"), "%" + searchText + "%")
);
};
return purchaseOrderRepository.findAll(spec, Pageable.ofSize(10)).getContent();
}
}

View File

@@ -0,0 +1,105 @@
package com.ecep.contract.ds.contract.service;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import com.ecep.contract.IEntityService;
import com.ecep.contract.ds.contract.repository.SalesOrderRepository;
import com.ecep.contract.model.Contract;
import com.ecep.contract.model.SalesOrder;
/**
* 合同服务
*/
@Lazy
@Service
@CacheConfig(cacheNames = "contract-sale-order")
public class SaleOrdersService implements IEntityService<SalesOrder> {
private static final Logger logger = LoggerFactory.getLogger(SaleOrdersService.class);
@Lazy
@Autowired
private SalesOrderRepository salesOrderRepository;
@Cacheable(key = "#p0")
public SalesOrder findById(Integer id) {
return salesOrderRepository.findById(id).orElse(null);
}
@Override
public Specification<SalesOrder> getSpecification(String searchText) {
if (!StringUtils.hasText(searchText)) {
return null;
}
return (root, query, builder) -> {
return builder.or(
builder.like(root.get("name"), "%" + searchText + "%"),
builder.like(root.get("code"), "%" + searchText + "%"));
};
}
@Cacheable(key = "'code-'+#p0")
public SalesOrder findByCode(String code) {
return salesOrderRepository.findByCode(code).orElse(null);
}
/**
* 保存实体对象,异步方法
*
* @param order 要保存的实体对象
* @return 返回异步调用
*/
@Caching(evict = {
@CacheEvict(key = "#p0.id"),
@CacheEvict(key = "'code-'+#p0.code")
})
public SalesOrder save(SalesOrder order) {
return salesOrderRepository.save(order);
}
@Caching(evict = {
@CacheEvict(key = "#p0.id"),
@CacheEvict(key = "'code-'+#p0.code")
})
public void delete(SalesOrder order) {
salesOrderRepository.delete(order);
}
public long count() {
return salesOrderRepository.count();
}
public long count(Specification<SalesOrder> spec) {
return salesOrderRepository.count(spec);
}
public Page<SalesOrder> findAll(Specification<SalesOrder> spec, Pageable pageable) {
return salesOrderRepository.findAll(spec, pageable);
}
public List<SalesOrder> findAll(Specification<SalesOrder> spec, Sort sort) {
return salesOrderRepository.findAll(spec, sort);
}
public List<SalesOrder> findAllByContract(Contract contract) {
return salesOrderRepository.findAllByContract(contract);
}
public List<SalesOrder> search(String searchText) {
return salesOrderRepository.findAll(getSpecification(searchText), Pageable.ofSize(10)).getContent();
}
}

View File

@@ -0,0 +1,164 @@
package com.ecep.contract.ds.contract.service;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import com.ecep.contract.IEntityService;
import com.ecep.contract.ds.contract.repository.SalesBillVoucherItemRepository;
import com.ecep.contract.ds.contract.repository.SalesBillVoucherRepository;
import com.ecep.contract.model.SalesBillVoucher;
import com.ecep.contract.model.SalesBillVoucherItem;
/**
* 采购账单凭证服务
*/
@Lazy
@Service
@CacheConfig(cacheNames = "sales-bill-voucher")
public class SalesBillVoucherService implements IEntityService<SalesBillVoucher> {
private static final Logger logger = LoggerFactory.getLogger(SalesBillVoucherService.class);
@Lazy
@Autowired
private SalesBillVoucherRepository salesBillVoucherRepository;
@Lazy
@Autowired
private SalesBillVoucherItemRepository salesBillVoucherItemRepository;
@Cacheable(key = "#p0")
public SalesBillVoucher findById(Integer id) {
return salesBillVoucherRepository.findById(id).orElse(null);
}
@Override
public Specification<SalesBillVoucher> getSpecification(String searchText) {
if (!StringUtils.hasText(searchText)) {
return null;
}
return (root, query, builder) -> {
return builder.or(
builder.like(root.get("name"), "%" + searchText + "%"),
builder.like(root.get("code"), "%" + searchText + "%")
);
};
}
@Cacheable(key = "'code-'+#p0")
public SalesBillVoucher findByCode(String code) {
return salesBillVoucherRepository.findByCode(code).orElse(null);
}
/**
* 保存实体对象,异步方法
*
* @param voucher 要保存的实体对象
* @return 返回异步调用
*/
@Caching(
evict = {
@CacheEvict(key = "#p0.id"),
@CacheEvict(key = "'code-'+#p0.code")
}
)
public SalesBillVoucher save(SalesBillVoucher voucher) {
return salesBillVoucherRepository.save(voucher);
}
@Caching(
evict = {
@CacheEvict(key = "#p0.id"),
@CacheEvict(key = "'code-'+#p0.code")
}
)
public void delete(SalesBillVoucher order) {
salesBillVoucherRepository.delete(order);
}
public long count() {
return salesBillVoucherRepository.count();
}
public long count(Specification<SalesBillVoucher> spec) {
return salesBillVoucherRepository.count(spec);
}
public Page<SalesBillVoucher> findAll(Specification<SalesBillVoucher> spec, Pageable pageable) {
return salesBillVoucherRepository.findAll(spec, pageable);
}
public List<SalesBillVoucher> findAll(Specification<SalesBillVoucher> spec, Sort sort) {
return salesBillVoucherRepository.findAll(spec, sort);
}
public List<SalesBillVoucher> search(String searchText) {
Specification<SalesBillVoucher> spec = (root, query, builder) -> {
return builder.or(
builder.like(root.get("name"), "%" + searchText + "%"),
builder.like(root.get("code"), "%" + searchText + "%")
);
};
return salesBillVoucherRepository.findAll(spec, Pageable.ofSize(10)).getContent();
}
@Cacheable(key = "'item-'+#p0")
public SalesBillVoucherItem findItemById(Integer id) {
return salesBillVoucherItemRepository.findById(id).orElse(null);
}
/**
* 保存实体对象,异步方法
*
* @param item 要保存的实体对象
* @return 返回异步调用
*/
@Caching(
evict = {
@CacheEvict(key = "'item-'+#p0.id")
}
)
public SalesBillVoucherItem save(SalesBillVoucherItem item) {
return salesBillVoucherItemRepository.save(item);
}
@Caching(
evict = {
@CacheEvict(key = "'item-'+#p0.id")
}
)
public void delete(SalesBillVoucherItem order) {
salesBillVoucherItemRepository.delete(order);
}
public long countItems() {
return salesBillVoucherItemRepository.count();
}
public long countItems(Specification<SalesBillVoucherItem> spec) {
return salesBillVoucherItemRepository.count(spec);
}
public Page<SalesBillVoucherItem> findAllItems(Specification<SalesBillVoucherItem> spec, Pageable pageable) {
return salesBillVoucherItemRepository.findAll(spec, pageable);
}
public List<SalesBillVoucherItem> findAllItems(Specification<SalesBillVoucherItem> spec, Sort sort) {
return salesBillVoucherItemRepository.findAll(spec, sort);
}
}

View File

@@ -0,0 +1,74 @@
package com.ecep.contract.ds.contract.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import com.ecep.contract.IEntityService;
import com.ecep.contract.ds.contract.repository.SalesOrderItemRepository;
import com.ecep.contract.model.SalesOrderItem;
@Lazy
@Service
@CacheConfig(cacheNames = "contract-sale-order-item")
public class SalesOrderItemService implements IEntityService<SalesOrderItem> {
@Lazy
@Autowired
private SalesOrderItemRepository repository;
@Cacheable(key = "#p0")
@Override
public SalesOrderItem findById(Integer id) {
return repository.findById(id).orElse(null);
}
@Override
public Specification<SalesOrderItem> getSpecification(String searchText) {
return (root, query, builder) -> {
return builder.or(
builder.like(root.get("code"), "%" + searchText + "%"),
builder.like(root.get("name"), "%" + searchText + "%"),
builder.like(root.get("description"), "%" + searchText + "%")
);
};
}
@Override
public Page<SalesOrderItem> findAll(Specification<SalesOrderItem> spec, Pageable pageable) {
return repository.findAll(spec, pageable);
}
@Caching(
evict = {
@CacheEvict(key = "#p0.id"),
}
)
@Override
public void delete(SalesOrderItem entity) {
repository.delete(entity);
}
@Caching(
evict = {
@CacheEvict(key = "#p0.id"),
}
)
@Override
public SalesOrderItem save(SalesOrderItem entity) {
return repository.save(entity);
}
public List<SalesOrderItem> findAll(Specification<SalesOrderItem> spec, Sort sort) {
return repository.findAll(spec, sort);
}
}

View File

@@ -0,0 +1,320 @@
package com.ecep.contract.ds.contract.tasker;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
import org.hibernate.Hibernate;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.jdbc.CannotGetJdbcConnectionException;
import org.springframework.util.StringUtils;
import com.ecep.contract.ContractPayWay;
import com.ecep.contract.MessageHolder;
import com.ecep.contract.SpringApp;
import com.ecep.contract.cloud.u8.YongYouU8Service;
import com.ecep.contract.cloud.u8.ctx.ContractCtx;
import com.ecep.contract.cloud.u8.ctx.PurchaseBillVoucherCtx;
import com.ecep.contract.cloud.u8.ctx.PurchaseOrderCtx;
import com.ecep.contract.cloud.u8.ctx.SalesBillVoucherCtx;
import com.ecep.contract.cloud.u8.ctx.SalesOrderCtx;
import com.ecep.contract.constant.CloudServiceConstant;
import com.ecep.contract.ds.contract.service.ContractService;
import com.ecep.contract.model.Contract;
import com.ecep.contract.model.Project;
import com.ecep.contract.model.SalesOrder;
import com.ecep.contract.ui.Tasker;
import lombok.Getter;
public abstract class AbstContractRepairTasker extends Tasker<Object> {
@Getter
protected boolean filesUpdated = false;
@Getter
protected boolean itemsUpdated = false;
@Getter
protected boolean playPlanUpdated = false;
@Getter
protected boolean saleOrderUpdated = false;
protected final ContractCtx contractCtx = new ContractCtx();
protected SalesOrderCtx salesOrderCtx = null;
protected SalesBillVoucherCtx salesBillVoucherCtx = null;
protected PurchaseOrderCtx purchaseOrderCtx = null;
protected PurchaseBillVoucherCtx purchaseBillVoucherCtx = null;
SalesOrderCtx getSalesOrderCtx() {
if (salesOrderCtx == null) {
salesOrderCtx = new SalesOrderCtx();
salesOrderCtx.from(contractCtx);
}
return salesOrderCtx;
}
SalesBillVoucherCtx getSalesBillVoucherCtx() {
if (salesBillVoucherCtx == null) {
salesBillVoucherCtx = new SalesBillVoucherCtx();
salesBillVoucherCtx.from(contractCtx);
}
return salesBillVoucherCtx;
}
PurchaseOrderCtx getPurchaseOrderCtx() {
if (purchaseOrderCtx == null) {
purchaseOrderCtx = new PurchaseOrderCtx();
purchaseOrderCtx.from(contractCtx);
}
return purchaseOrderCtx;
}
PurchaseBillVoucherCtx getPurchaseBillVoucherCtx() {
if (purchaseBillVoucherCtx == null) {
purchaseBillVoucherCtx = new PurchaseBillVoucherCtx();
purchaseBillVoucherCtx.from(contractCtx);
}
return purchaseBillVoucherCtx;
}
public void setContractService(ContractService contractService) {
contractCtx.setContractService(contractService);
}
@Override
protected Object execute(MessageHolder holder) throws Exception {
try {
YongYouU8Service u8Service = SpringApp.getBean(YongYouU8Service.class);
u8Service.initialize(contractCtx);
} catch (NoSuchBeanDefinitionException ignored) {
holder.warn("无法使用 " + CloudServiceConstant.U8_NAME + " 服务");
}
try {
repair(holder);
} catch (CannotGetJdbcConnectionException e) {
throw new RuntimeException("无法获取的数据库连接", e);
}
return null;
}
protected abstract void repair(MessageHolder holder);
/**
* rs 数据从 CM_List 表中读取
*/
protected boolean repairFromCMList(Map<String, Object> rs, MessageHolder holder) {
String contractID = (String) rs.get("strContractID");
String guid = (String) rs.get("GUID");
String contractName = (String) rs.get("strContractName");
String state = (String) rs.get("strState");
holder.info("同步合同 " + contractID + " " + contractName);
Contract contract = contractCtx.findOrCreatByGuidOrContractId(guid, contractID, holder);
if (contract == null) {
holder.warn("未知合同" + contractID + ", " + rs.get("strContractName"));
return false;
}
boolean modified = false;
if (contractCtx.updateText(contract::getCode, contract::setCode, contractID, holder, "合同编号")) {
ContractService contractService = contractCtx.getContractService();
Contract dup = contractService.findByCode(contractID);
if (dup != null) {
if (!Objects.equals(contract, dup)) {
contractService.delete(dup);
holder.warn("删除重复的合同 " + dup);
}
}
modified = true;
}
if (contractCtx.updateText(contract::getGuid, contract::setGuid, guid, holder, "GUID")) {
ContractService contractService = contractCtx.getContractService();
Contract dup = contractService.findByGuid(guid);
if (dup != null) {
if (!Objects.equals(contract, dup)) {
contractService.delete(dup);
holder.warn("删除重复的合同 " + dup);
}
}
modified = true;
}
if (contractCtx.updateText(contract::getState, contract::setState, state, holder, "合同状态")) {
modified = true;
}
if (modified) {
contract = contractCtx.save(contract);
}
Contract parent = null;
if (contract.getPayWay() == ContractPayWay.PAY) {
if (StringUtils.hasText(contract.getParentCode())) {
parent = contractCtx.findContractByCode(contract.getParentCode());
}
}
AtomicReference<Contract> refer = new AtomicReference<>(contract);
try {
return repair(refer, parent, holder, progress -> {
});
} catch (Exception e) {
holder.error(state);
return false;
}
}
/**
* @param contractProperty
* @param holder
* @param progress
* @return
*/
public boolean repair(
AtomicReference<Contract> contractProperty,
Contract parent, MessageHolder holder, Consumer<Double> progress) {
boolean repaired = false;
boolean modified = false;
Contract contract = contractProperty.get();
progress.accept(0.1);
if (contractCtx.updateContractDetailByGuid(contract, contract.getGuid(), holder)) {
modified = true;
}
progress.accept(0.2);
if (contractCtx.updateContractExec(contract, holder)) {
modified = true;
}
progress.accept(0.3);
if (contractCtx.updateContractAmount(contract, holder)) {
modified = true;
}
progress.accept(0.4);
if (contractCtx.updateParentContract(contract, holder)) {
modified = true;
}
if (contractCtx.updateContractPath(contract, holder)) {
modified = true;
}
progress.accept(0.5);
if (modified) {
contract = contractCtx.save(contract);
contractProperty.set(contract);
modified = false;
repaired = true;
}
progress.accept(0.6);
if (contractCtx.syncContractItems(contract, holder)) {
itemsUpdated = true;
modified = true;
}
progress.accept(0.66);
if (contractCtx.syncContractPayPlan(contract, holder)) {
playPlanUpdated = true;
}
progress.accept(0.7);
if (contractCtx.updateContractProject(contract, parent, holder)) {
modified = true;
}
if (modified) {
contract = contractCtx.save(contract);
contractProperty.set(contract);
modified = false;
repaired = true;
}
progress.accept(0.8);
// 销售合同
if (contract.getPayWay() == ContractPayWay.RECEIVE) {
syncSaleOrder(contract, holder);
syncChildrenContract(contract, holder, p -> progress.accept(p * 0.1 + 0.8));
} else if (contract.getPayWay() == ContractPayWay.PAY) {
syncPurchaseOrder(contract, holder);
}
progress.accept(0.9);
if (contractCtx.syncContractFiles(contract, holder)) {
filesUpdated = true;
repaired = true;
}
progress.accept(1.0);
return repaired;
}
private void syncChildrenContract(Contract parent, MessageHolder holder, Consumer<Double> progress) {
ContractService contractService = contractCtx.getContractService();
List<Contract> list = contractService.findAllByParent(parent);
for (int i = 0; i < list.size(); i++) {
Contract v = list.get(i);
holder.info("子合同 " + v.getCode() + " " + v.getName());
MessageHolder subHolder = holder.sub(" -- ");
boolean modified = false;
Project project = parent.getProject();
if (project == null) {
project = v.getProject();
}
AtomicReference<Contract> contractProperty = new AtomicReference<>(v);
try {
repair(contractProperty, parent, subHolder, p -> {
});
v = contractProperty.get();
if (contractCtx.updateContractProject(v, project, subHolder)) {
modified = true;
}
} catch (Exception e) {
if (!Hibernate.isInitialized(v)) {
v = contractService.findById(v.getId());
}
throw new RuntimeException("同步子合同失败, contract=" + v.toPrettyString(), e);
}
if (modified) {
try {
v = contractCtx.save(v);
} catch (Exception e) {
throw new RuntimeException("#" + v.getId() + ", v=" + v.getVersion(), e);
}
modified = false;
}
progress.accept((double) i / list.size());
}
}
/**
* 同步合同的销售订单
*
* @param contract 合同
* @param holder 消息
*/
private void syncSaleOrder(Contract contract, MessageHolder holder) {
SalesOrderCtx ctx = getSalesOrderCtx();
if (ctx.getRepository() == null) {
return;
}
List<SalesOrder> orders = ctx.syncByContract(contract, holder);
if (orders == null) {
return;
}
SalesBillVoucherCtx voucherCtx = getSalesBillVoucherCtx();
for (SalesOrder order : orders) {
voucherCtx.syncBySalesOrder(order, holder);
}
}
/**
* 同步合同采购订单
*
* @param contract 合同
* @param holder 消息
*/
private void syncPurchaseOrder(Contract contract, MessageHolder holder) {
PurchaseOrderCtx ctx1 = getPurchaseOrderCtx();
if (ctx1.getRepository() != null) {
ctx1.syncByContract(contract, holder);
}
PurchaseBillVoucherCtx ctx2 = getPurchaseBillVoucherCtx();
if (ctx2.getRepository() != null) {
ctx2.syncByContract(contract, holder);
}
}
}

View File

@@ -0,0 +1,90 @@
package com.ecep.contract.ds.contract.tasker;
import java.util.concurrent.atomic.AtomicInteger;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import com.ecep.contract.MessageHolder;
import com.ecep.contract.cloud.u8.ctx.ContractCtx;
import com.ecep.contract.ds.contract.service.ContractService;
import com.ecep.contract.model.Contract;
import com.ecep.contract.model.ContractGroup;
import com.ecep.contract.ui.Tasker;
import lombok.Setter;
/**
* 对所有合同的文件进行重置
*/
public class ContractFilesRebuildAllTasker extends Tasker<Object> {
@Setter
private ContractService contractService;
private ContractCtx contractCtx;
@Setter
private ContractGroup group;
ContractCtx getContractCtx() {
if (contractCtx == null) {
contractCtx = new ContractCtx();
contractCtx.setContractService(getContractService());
}
return contractCtx;
}
public ContractFilesRebuildAllTasker() {
updateTitle("合同文件重置");
}
@Override
protected Object execute(MessageHolder holder) {
Pageable pageRequest = PageRequest.ofSize(200);
AtomicInteger counter = new AtomicInteger(0);
updateTitle("遍历所有合同,对每个可以合同的文件进行“重置”操作");
Specification<Contract> spec = null;
if (group != null) {
holder.info("= 按合同分组 " + group.getTitle() + " 刷选 =");
spec = (root, query, cb) -> {
return cb.equal(root.get("group"), group);
};
}
long total = getContractService().count(spec);
while (true) {
if (isCancelled()) {
break;
}
Page<Contract> page = getContractService().findAll(spec, pageRequest);
if (page.isEmpty()) {
break;
}
for (Contract contract : page) {
if (isCancelled()) {
break;
}
MessageHolder subHolder = holder.sub(
counter.get() + " / " + total + "> " + contract.getCode() + " #" + contract.getId() + "> ");
getContractCtx().syncContractFiles(contract, subHolder);
updateProgress(counter.incrementAndGet(), total);
}
if (!page.hasNext()) {
break;
}
pageRequest = page.nextPageable();
}
return null;
}
private ContractService getContractService() {
if (contractService == null) {
contractService = getBean(ContractService.class);
}
return contractService;
}
}

View File

@@ -0,0 +1,46 @@
package com.ecep.contract.ds.contract.tasker;
import com.ecep.contract.MessageHolder;
import com.ecep.contract.cloud.u8.ctx.ContractCtx;
import com.ecep.contract.ds.contract.service.ContractService;
import com.ecep.contract.model.Contract;
import com.ecep.contract.ui.Tasker;
import lombok.Getter;
import lombok.Setter;
/**
* 对合同的文件进行重置
*/
public class ContractFilesRebuildTasker extends Tasker<Object> {
@Setter
private ContractService contractService;
@Setter
private Contract contract;
@Getter
private boolean repaired = false;
public ContractFilesRebuildTasker() {
updateTitle("合同文件重置");
}
@Override
protected Object execute(MessageHolder holder) {
updateTitle("遍历合同的文件进行“重置”操作");
ContractCtx contractCtx = new ContractCtx();
if (contractCtx.syncContractFiles(contract, holder)) {
repaired = true;
}
return null;
}
private ContractService getContractService() {
if (contractService == null) {
contractService = getBean(ContractService.class);
}
return contractService;
}
}

View File

@@ -0,0 +1,115 @@
package com.ecep.contract.ds.contract.tasker;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.logging.Level;
import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.util.StringUtils;
import com.ecep.contract.ContractPayWay;
import com.ecep.contract.Message;
import com.ecep.contract.MessageHolder;
import com.ecep.contract.ds.contract.service.ContractService;
import com.ecep.contract.model.Contract;
import jakarta.persistence.criteria.Path;
/**
* 对所有合同进行修复
*/
public class ContractRepairAllTasker extends AbstContractRepairTasker {
private static final Logger logger = LoggerFactory.getLogger(ContractRepairAllTasker.class);
static class MessageHolderImpl implements MessageHolder {
List<Message> messages = new ArrayList<>();
@Override
public void addMessage(Level level, String message) {
Message msg = new Message(level, message);
messages.add(msg);
}
}
@Override
protected void repair(MessageHolder holder) {
updateTitle("同步修复所有合同");
Pageable pageRequest = PageRequest.ofSize(200);
AtomicInteger counter = new AtomicInteger(0);
Specification<Contract> spec = (root, query, builder) -> {
Path<String> parentCode = root.get("parentCode");
Path<ContractPayWay> payWay = root.get("payWay");
return builder.or(
builder.equal(payWay, ContractPayWay.RECEIVE),
builder.and(
builder.equal(payWay, ContractPayWay.PAY),
builder.or(
builder.equal(parentCode, ""),
builder.isNull(parentCode))));
};
updateTitle("遍历所有合同,对每个可以合同的文件进行“修复”操作");
ContractService contractService = contractCtx.getContractService();
long total = contractService.count(spec);
while (true) {
if (isCancelled()) {
break;
}
Page<Contract> page = contractService.findAll(spec, pageRequest);
if (page.isEmpty()) {
break;
}
for (Contract contract : page) {
if (isCancelled()) {
break;
}
MessageHolder subHolder = holder.sub(
counter.get() + " / " + total + "> " + contract.getCode() + " #" + contract.getId() + "> ");
MessageHolderImpl messageHolder = new MessageHolderImpl();
try {
Contract parent = null;
if (contract.getPayWay() == ContractPayWay.PAY) {
if (StringUtils.hasText(contract.getParentCode())) {
parent = contractCtx.findContractByCode(contract.getParentCode());
}
}
AtomicReference<Contract> contractProperty = new AtomicReference<>(contract);
boolean repaired = repair(contractProperty, parent, messageHolder, progress -> {
});
String msg = messageHolder.messages.stream()
.filter(v -> v.getLevel().intValue() > Level.INFO.intValue())
.map(Message::getMessage)
.collect(Collectors.joining(", "));
if (StringUtils.hasText(msg)) {
if (repaired) {
subHolder.info(msg);
} else {
subHolder.error(msg);
}
}
} catch (Exception e) {
subHolder.error("修复失败 #" + contract.getCode() + ": " + e.getMessage());
if (logger.isErrorEnabled()) {
logger.error(contract.getCode(), e);
}
}
updateProgress(counter.incrementAndGet(), total);
}
if (!page.hasNext()) {
break;
}
pageRequest = page.nextPageable();
}
}
}

View File

@@ -0,0 +1,70 @@
package com.ecep.contract.ds.contract.tasker;
import java.time.Instant;
import java.time.LocalDate;
import org.springframework.beans.BeansException;
import com.ecep.contract.MessageHolder;
import com.ecep.contract.cloud.u8.YongYouU8Service;
import com.ecep.contract.cloud.u8.ctx.CustomerCtx;
import com.ecep.contract.cloud.u8.ctx.VendorCtx;
import com.ecep.contract.constant.CloudServiceConstant;
import com.ecep.contract.model.CloudYu;
import com.ecep.contract.model.Company;
import lombok.Getter;
import lombok.Setter;
public class ContractRepairByCompanyTask extends AbstContractRepairTasker {
@Getter
@Setter
private Company company;
@Setter
private YongYouU8Service yongYouU8Service;
@Getter
boolean repaired = false;
@Override
protected void repair(MessageHolder holder) {
updateTitle("同步修复 " + company.getName() + " 下的所有合同");
try {
yongYouU8Service = getBean(YongYouU8Service.class);
} catch (BeansException e) {
holder.warn("未启用 " + CloudServiceConstant.U8_NAME + " 服务");
return;
}
CloudYu cloudYu = yongYouU8Service.getOrCreateCloudYu(company);
if (cloudYu == null) {
holder.error("无法创建或获取 CloudYu 对象");
return;
}
try {
VendorCtx vendorCtx = new VendorCtx();
vendorCtx.from(contractCtx);
if (vendorCtx.syncVendor(company, holder)) {
cloudYu.setVendorUpdateDate(LocalDate.now());
repaired = true;
}
CustomerCtx customerCtx = new CustomerCtx();
customerCtx.from(contractCtx);
if (customerCtx.syncCustomer(company, holder)) {
cloudYu.setCustomerUpdateDate(LocalDate.now());
repaired = true;
}
cloudYu.setCloudLatest(Instant.now());
cloudYu.setExceptionMessage("");
} catch (Exception e) {
cloudYu.setExceptionMessage(e.getMessage());
} finally {
cloudYu.setLatestUpdate(Instant.now());
yongYouU8Service.save(cloudYu);
}
}
}

View File

@@ -0,0 +1,147 @@
package com.ecep.contract.ds.contract.tasker;
import static com.ecep.contract.SpringApp.getBean;
import java.io.File;
import org.springframework.util.StringUtils;
import com.ecep.contract.MessageHolder;
import com.ecep.contract.SpringApp;
import com.ecep.contract.ds.company.CompanyFileUtils;
import com.ecep.contract.ds.company.service.CompanyService;
import com.ecep.contract.ds.contract.service.ContractService;
import com.ecep.contract.ds.project.service.ProjectService;
import com.ecep.contract.model.Company;
import com.ecep.contract.model.Contract;
import com.ecep.contract.model.ContractCatalog;
import com.ecep.contract.model.Project;
import lombok.Data;
import lombok.Setter;
@Data
public class ContractRepairComm {
@Setter
private ProjectService projectService;
@Setter
private CompanyService companyService;
@Setter
private ContractService contractService;
public ContractService getContractService() {
if (contractService == null) {
contractService = getBean(ContractService.class);
}
return contractService;
}
public ProjectService getProjectService() {
if (projectService == null) {
projectService = SpringApp.getBean(ProjectService.class);
}
return projectService;
}
private CompanyService getCompanyService() {
if (companyService == null) {
companyService = SpringApp.getBean(CompanyService.class);
}
return companyService;
}
/**
* 创建合同目录
*
* @param contract 合同对象
* @return 合同目录
*/
public boolean makePathAbsent(Contract contract, MessageHolder holder) {
if (CompanyFileUtils.exists(contract.getPath())) {
return false;
}
File dir = makePath(contract, holder);
if (dir == null) {
return false;
}
if (!dir.exists()) {
return false;
}
contract.setPath(dir.getAbsolutePath());
return true;
}
public Contract save(Contract contract) {
return getContractService().save(contract);
}
public Project save(Project project) {
return getProjectService().save(project);
}
public File makePath(Contract contract, MessageHolder holder) {
File parentDir = null;
String contractDirName = contract.getCode();
if (getContractService().isSubContract(contract)) {
// 子合同,需要在主合同目录下
String parentCode = contract.getParentCode();
if (!StringUtils.hasText(parentCode)) {
return null;
}
Contract parent = getContractService().findByCode(parentCode);
if (parent == null) {
return null;
}
String parentPath = parent.getPath();
if (!StringUtils.hasText(parentPath)) {
if (makePathAbsent(parent, holder)) {
parent = save(parent);
parentPath = parent.getPath();
} else {
return null;
}
}
parentDir = new File(parentPath);
} else {
// 主合同
ContractCatalog catalog = getContractService().findContractCatalogByContract(contract);
if (catalog == null) {
return null;
}
File catalogPath = getContractService().getContractCatalogPath(catalog, contract);
if (catalogPath == null) {
return null;
}
parentDir = catalogPath;
contractDirName = contract.getCode() + "-" + CompanyFileUtils.escapeFileName(contract.getName());
}
File path = new File(parentDir, contractDirName);
if (!path.exists()) {
if (!path.mkdir()) {
//
holder.warn("unable make directory = " + path.getAbsolutePath());
return null;
}
}
return path;
}
public Project findProjectById(Integer projectId) {
return getProjectService().findById(projectId);
}
public Company findCompanyById(Integer companyId) {
return getCompanyService().findById(companyId);
}
public Contract findContractByGuid(String guid) {
return contractService.findByGuid(guid);
}
}

View File

@@ -0,0 +1,52 @@
package com.ecep.contract.ds.contract.tasker;
import java.util.concurrent.atomic.AtomicReference;
import org.springframework.util.StringUtils;
import com.ecep.contract.ContractPayWay;
import com.ecep.contract.MessageHolder;
import com.ecep.contract.model.Contract;
import lombok.Getter;
import lombok.Setter;
/**
* 合同修复任务
*/
public class ContractRepairTask extends AbstContractRepairTasker {
@Getter
@Setter
private Contract contract;
@Getter
boolean repaired = false;
private final ContractRepairComm comm = new ContractRepairComm();
public ContractRepairTask() {
}
@Override
protected void repair(MessageHolder holder) {
updateTitle("修复合同 " + contract.toPrettyString());
Contract parent = null;
if (contract.getPayWay() == ContractPayWay.PAY) {
if (StringUtils.hasText(contract.getParentCode())) {
parent = contractCtx.findContractByCode(contract.getParentCode());
}
}
AtomicReference<Contract> contractProperty = new AtomicReference<>(contract);
if (repair(contractProperty, parent, holder, progress -> updateProgress(progress, 1))) {
repaired = true;
}
setContract(contractProperty.get());
updateProgress(1, 1);
}
}

View File

@@ -0,0 +1,848 @@
package com.ecep.contract.ds.contract.tasker;
import com.ecep.contract.*;
import com.ecep.contract.ds.company.CompanyFileUtils;
import com.ecep.contract.ds.company.service.CompanyExtendInfoService;
import com.ecep.contract.ds.company.service.CompanyFileService;
import com.ecep.contract.ds.company.service.CompanyService;
import com.ecep.contract.ds.contract.service.ContractBidVendorService;
import com.ecep.contract.ds.contract.service.ContractFileService;
import com.ecep.contract.ds.contract.service.ContractService;
import com.ecep.contract.ds.contract.service.ExtendVendorInfoService;
import com.ecep.contract.ds.customer.service.CompanyCustomerFileService;
import com.ecep.contract.ds.customer.service.CompanyCustomerService;
import com.ecep.contract.ds.other.service.EmployeeService;
import com.ecep.contract.ds.project.ProjectCostImportItemsFromContractsTasker;
import com.ecep.contract.ds.project.service.*;
import com.ecep.contract.ds.vendor.service.CompanyVendorService;
import com.ecep.contract.ds.vendor.service.VendorGroupRequireFileTypeService;
import com.ecep.contract.ds.vendor.service.VendorGroupService;
import com.ecep.contract.model.*;
import com.ecep.contract.util.NumberStringConverter;
import lombok.Data;
import org.hibernate.Hibernate;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.util.StringUtils;
import java.io.File;
import java.text.NumberFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;
import java.util.stream.Collectors;
@Data
public class ContractVerifyComm {
// Project
private ProjectService projectService;
private ProjectSaleTypeRequireFileTypeService saleTypeRequireFileTypeService;
private SaleTypeService saleTypeService;
private ProjectCostService projectCostService;
private ProjectQuotationService projectQuotationService;
private ProjectBidService projectBidService;
// Contract
private ContractService contractService;
private ContractFileService contractFileService;
private ContractBidVendorService contractBidVendorService;
// Company
private CompanyService companyService;
private CompanyFileService companyFileService;
// Vendor
private CompanyVendorService companyVendorService;
private VendorGroupService vendorGroupService;
private VendorGroupRequireFileTypeService vendorGroupRequireFileTypeService;
private ExtendVendorInfoService extendVendorInfoService;
// Customer
private CompanyCustomerService companyCustomerService;
private CompanyCustomerFileService companyCustomerFileService;
private CompanyExtendInfoService companyExtendInfoService;
// Employee
private EmployeeService employeeService;
private ProjectService getProjectService() {
if (projectService == null) {
projectService = SpringApp.getBean(ProjectService.class);
}
return projectService;
}
private SaleTypeService getSaleTypeService() {
if (saleTypeService == null) {
saleTypeService = SpringApp.getBean(SaleTypeService.class);
}
return saleTypeService;
}
ProjectCostService getProjectCostService() {
if (projectCostService == null) {
projectCostService = SpringApp.getBean(ProjectCostService.class);
}
return projectCostService;
}
ProjectQuotationService getProjectQuotationService() {
if (projectQuotationService == null) {
projectQuotationService = SpringApp.getBean(ProjectQuotationService.class);
}
return projectQuotationService;
}
ProjectBidService getProjectBidService() {
if (projectBidService == null) {
projectBidService = SpringApp.getBean(ProjectBidService.class);
}
return projectBidService;
}
private ProjectSaleTypeRequireFileTypeService getSaleTypeRequireFileTypeService() {
if (saleTypeRequireFileTypeService == null) {
saleTypeRequireFileTypeService = SpringApp.getBean(ProjectSaleTypeRequireFileTypeService.class);
}
return saleTypeRequireFileTypeService;
}
public ContractService getContractService() {
if (contractService == null) {
contractService = SpringApp.getBean(ContractService.class);
}
return contractService;
}
private ContractFileService getContractFileService() {
if (contractFileService == null) {
contractFileService = SpringApp.getBean(ContractFileService.class);
}
return contractFileService;
}
private ContractBidVendorService getContractBidVendorService() {
if (contractBidVendorService == null) {
contractBidVendorService = SpringApp.getBean(ContractBidVendorService.class);
}
return contractBidVendorService;
}
private CompanyService getCompanyService() {
if (companyService == null) {
companyService = SpringApp.getBean(CompanyService.class);
}
return companyService;
}
private CompanyFileService getCompanyFileService() {
if (companyFileService == null) {
companyFileService = SpringApp.getBean(CompanyFileService.class);
}
return companyFileService;
}
private VendorGroupService getVendorGroupService() {
if (vendorGroupService == null) {
vendorGroupService = SpringApp.getBean(VendorGroupService.class);
}
return vendorGroupService;
}
private VendorGroupRequireFileTypeService getVendorGroupRequireFileTypeService() {
if (vendorGroupRequireFileTypeService == null) {
vendorGroupRequireFileTypeService = SpringApp.getBean(VendorGroupRequireFileTypeService.class);
}
return vendorGroupRequireFileTypeService;
}
private ExtendVendorInfoService getExtendVendorInfoService() {
if (extendVendorInfoService == null) {
extendVendorInfoService = SpringApp.getBean(ExtendVendorInfoService.class);
}
return extendVendorInfoService;
}
private CompanyVendorService getCompanyVendorService() {
if (companyVendorService == null) {
companyVendorService = SpringApp.getBean(CompanyVendorService.class);
}
return companyVendorService;
}
private CompanyCustomerService getCompanyCustomerService() {
if (companyCustomerService == null) {
companyCustomerService = SpringApp.getBean(CompanyCustomerService.class);
}
return companyCustomerService;
}
private CompanyCustomerFileService getCompanyCustomerFileService() {
if (companyCustomerFileService == null) {
companyCustomerFileService = SpringApp.getBean(CompanyCustomerFileService.class);
}
return companyCustomerFileService;
}
private CompanyExtendInfoService getCompanyExtendInfoService() {
if (companyExtendInfoService == null) {
companyExtendInfoService = SpringApp.getBean(CompanyExtendInfoService.class);
}
return companyExtendInfoService;
}
private EmployeeService getEmployeeService() {
if (employeeService == null) {
employeeService = SpringApp.getBean(EmployeeService.class);
}
return employeeService;
}
/**
*
*/
private Map<ContractFileType, ContractFileTypeLocal> fileTypeLocalMap = null;
private Locale locale = Locale.getDefault();
private Contract contract;
/**
* 是否验证企业存储目录
*/
private boolean verifyCompanyPath = true;
/**
* 是否验证企业状态
*/
private boolean verifyCompanyStatus = true;
/**
* 是否验证企业文件(资信报告)
*/
private boolean verifyCompanyCredit = true;
/**
* 是否验证客户
*/
private boolean verifyCustomer = true;
/**
* 是否验证客户文件(合同文件)
*/
private boolean verifyCustomerFiles = true;
/**
* 是否验证客户子合同日期
*/
private boolean verifyCustomerSubContractDate = true;
/**
* 是否验证供应商
*/
private boolean verifyVendor = true;
/**
* 是否验证供应商文件(供应商合同)
*/
private boolean verifyVendorFiles = true;
/**
* 合同合规性检测
*
* @param contract 要验证的合同对象
* @param holder 输出
*/
public void verify(Contract contract, MessageHolder holder) {
LocalDate setupDate = contract.getSetupDate();
if (setupDate == null) {
holder.error("未设置合同提交日期");
return;
}
Company company = contract.getCompany();
if (company == null) {
holder.error("未关联企业");
return;
}
if (!Hibernate.isInitialized(company)) {
company = getCompanyService().findById(company.getId());
}
verify(company, contract, holder);
}
public void verify(Company company, Contract contract, MessageHolder holder) {
LocalDate setupDate = contract.getSetupDate();
Employee employee = contract.getEmployee();
if (employee == null) {
holder.error("未关联业务员");
}
if (contract.getAmount() == null || contract.getAmount() <= 0) {
holder.error("合同金额小于等于0");
}
CompanyExtendInfo companyExtendInfo = getCompanyExtendInfoService().findByCompany(company);
if (companyExtendInfo.isDisableVerify()) {
holder.debug("公司设定不做校验");
} else {
if (verifyCompanyPath) {
if (!CompanyFileUtils.exists(company.getPath())) {
holder.error("公司目录未设置");
} else {
File basePath = getCompanyService().getBasePath();
if (!company.getPath().startsWith(basePath.getAbsolutePath())) {
holder.error("公司目录未在规定目录下");
}
}
}
if (verifyCompanyStatus) {
getCompanyService().verifyEnterpriseStatus(company, setupDate, msg -> {
holder.error(company.getName() + ":" + msg);
});
}
if (verifyCompanyCredit) {
getCompanyFileService().verify(company, contract.getSetupDate(), msg -> {
holder.error(company.getName() + ":" + msg);
});
}
}
// 合同类型
switch (contract.getPayWay()) {
case RECEIVE -> {
// 销售合同
verifyAsCustomer(company, companyExtendInfo, contract, holder);
// 销售合同下的采购合同
List<Contract> list = getContractService().findAllByParent(contract);
if (!list.isEmpty()) {
for (Contract v : list) {
MessageHolder subHolder = holder.sub(v.getCode() + " -> ");
subHolder.info("采购合同 " + v.getName());
verify(v, subHolder);
if (CompanyFileUtils.exists(v.getPath())) {
if (!v.getPath().startsWith(contract.getPath())) {
holder.error("合同目录未在规定目录下");
}
} else {
holder.error("合同目录未设置");
}
}
DoubleSummaryStatistics statistics = list.stream().mapToDouble(c -> {
return Objects.requireNonNullElse(c.getAmount(), 0.0);
}).summaryStatistics();
NumberFormat numberFormat = NumberFormat.getCurrencyInstance(locale);
holder.debug("采购合同金额合计:" + numberFormat.format(statistics.getSum()));
holder.debug("采购合同金额平均值:" + numberFormat.format(statistics.getAverage()));
holder.debug("采购合同金额最大值:" + numberFormat.format(statistics.getMax()));
holder.debug("采购合同金额最小值:" + numberFormat.format(statistics.getMin()));
if (contract.getAmount() != null && statistics.getSum() > contract.getAmount()) {
holder.warn("采购合同金额合计大于销售合同金额");
}
}
break;
}
case PAY -> {
verifyAsVendor(company, contract, holder);
break;
}
case OTHER -> {
holder.error("合同付款类型:其他");
break;
}
default -> {
holder.error("合同付款类型:未设置");
}
}
}
private void verifyAsVendor(Company company, Contract contract, MessageHolder holder) {
// 供应商,检查评价表
ExtendVendorInfo vendorInfo = getExtendVendorInfoService().findByContract(contract);
if (vendorInfo == null) {
ExtendVendorInfo info = getExtendVendorInfoService().newInstanceByContract(contract);
vendorInfo = getExtendVendorInfoService().save(info);
holder.info("创建供应商信息 #" + vendorInfo.getId());
}
VendorGroup group = vendorInfo.getGroup();
boolean assignedProvider = vendorInfo.isAssignedProvider();
if (assignedProvider) {
holder.debug("采购信息中设定为指定供应商");
}
if (group != null) {
if (!Hibernate.isInitialized(group)) {
group = getVendorGroupService().findById(group.getId());
vendorInfo.setGroup(group);
}
}
if (verifyCustomerSubContractDate) {
// 检查子合同日期是否在销售合同之后
if (!vendorInfo.isPrePurchase()) {
String parentCode = contract.getParentCode();
if (StringUtils.hasText(parentCode)) {
Contract parent = getContractService().findByCode(parentCode);
if (parent != null) {
if (contract.getSetupDate().isBefore(parent.getSetupDate())) {
holder.warn("采购合同:" + contract.getCode() + " 提交日期在销售合同之前");
}
}
}
}
}
if (verifyVendor) {
getCompanyVendorService().verify(contract, holder);
}
if (verifyVendorFiles) {
holder.debug("核验文件...");
verifyVendorFile(group, assignedProvider, contract, holder);
}
}
private void verifyVendorFile(VendorGroup group, boolean assignedProvider, Contract contract,
MessageHolder holder) {
if (group == null) {
return;
}
boolean loseFile = false;
List<ContractFile> files = getContractFileService().findAllByContract(contract);
List<VendorGroupRequireFileType> list = getVendorGroupRequireFileTypeService().findByGroupId(group.getId());
if (list != null && !list.isEmpty()) {
for (VendorGroupRequireFileType item : list) {
ContractFileType fileType = item.getFileType();
if (fileType == null) {
continue;
}
if (fileType == ContractFileType.QuotationSheet && assignedProvider
&& group.isRequireQuotationSheetForBid()) {
continue;
}
if (!hasFileType(files, fileType)) {
holder.error("供应商" + getFileTypeLocalValue(fileType) + "未上传");
loseFile = true;
}
}
}
// 供应商比价
if (group.isPriceComparison()) {
if (assignedProvider) {
holder.debug("指定供应商, 跳过供应商比价");
} else {
boolean requireQuotation = group.isRequireQuotationSheetForBid();
List<ContractBidVendor> bidVendors = getContractBidVendorService().findByContract(contract);
if (bidVendors == null || bidVendors.isEmpty()) {
holder.error("未上报供应商比价");
} else {
for (ContractBidVendor bidVendor : bidVendors) {
ContractFile contractFile = bidVendor.getQuotationSheet();
if (contractFile == null) {
if (requireQuotation && bidVendor.getCompany().equals(contract.getCompany())) {
holder.debug("供应商类型启用了允许选中供应商不必须要有报价表");
} else {
holder.error("供应商比价:" + bidVendor.getCompany().getName() + " 未上传/关联报价表");
loseFile = true;
}
} else {
if (!Hibernate.isInitialized(contractFile)) {
contractFile = getContractFileService().findById(contractFile.getId());
}
ContractFileType type = contractFile.getType();
if (type != ContractFileType.QuotationSheet) {
holder.error("供应商比价:" + contractFile.getFileName() + " 报价表记录异常,类型错误");
}
File file = new File(contract.getPath(), contractFile.getFileName());
if (!file.exists()) {
holder.error("供应商比价:" + file.getName() + " 报价表记录异常,文件不存在");
loseFile = true;
}
}
}
}
}
}
if (loseFile && files.isEmpty()) {
holder.warn("!上传文件空!");
}
}
ContractFileTypeLocal getFileTypeLocal(ContractFileType type) {
if (fileTypeLocalMap == null) {
fileTypeLocalMap = getContractFileService().findAllFileTypes(getLocale().toLanguageTag());
}
return fileTypeLocalMap.get(type);
}
String getFileTypeLocalValue(ContractFileType type) {
ContractFileTypeLocal fileTypeLocal = getFileTypeLocal(type);
if (fileTypeLocal == null) {
return type.name();
}
return fileTypeLocal.getValue();
}
private boolean hasFileType(List<ContractFile> files, ContractFileType fileType) {
if (files == null || files.isEmpty()) {
return false;
}
for (ContractFile file : files) {
if (file.getType() == fileType) {
return true;
}
}
return false;
}
private void verifyAsCustomer(Company company, CompanyExtendInfo companyExtendInfo, Contract contract,
MessageHolder holder) {
boolean valiad = true;
Project project = contract.getProject();
if (project == null) {
// 收款的合同时,检查是否关联了项目,如果没有则创建
if (contract.getPayWay() == ContractPayWay.RECEIVE) {
project = getProjectService().findByCode(contract.getCode());
if (project == null) {
holder.info("创建关联项目");
try {
project = getProjectService().newInstanceByContract(contract);
project = getProjectService().save(project);
} catch (Exception e) {
holder.error("创建关联项目失败: " + e.getMessage());
throw new RuntimeException("code=" + contract.getCode(), e);
}
}
contract.setProject(project);
contract = getContractService().save(contract);
}
}
if (project != null) {
if (!Hibernate.isInitialized(project)) {
project = getProjectService().findById(project.getId());
// fixed
contract.setProject(project);
}
}
if (project != null) {
holder.info("验证项目信息:" + project.getCode() + " " + project.getName());
verifyProject(contract, project, holder.sub("项目"));
ProjectSaleType saleType = project.getSaleType();
if (saleType != null) {
if (CompanyFileUtils.exists(contract.getPath())) {
if (!Hibernate.isInitialized(saleType)) {
saleType = getSaleTypeService().findById(saleType.getId());
project.setSaleType(saleType);
}
if (!contract.getPath().startsWith(saleType.getPath())) {
holder.error("合同目录未在销售类型目录下");
}
}
}
}
if (!companyExtendInfo.isDisableVerify()) {
if (!verifyCustomerContract(contract, holder)) {
valiad = false;
}
if (verifyCustomerFiles) {
holder.debug("核验文件...");
if (!verifyContractFileAsCustomer(project, contract, holder)) {
valiad = false;
}
}
}
}
/**
* 客户,检查评估表
*/
private boolean verifyCustomerContract(Contract contract, MessageHolder holder) {
if (!verifyCustomer) {
return false;
}
boolean valid = true;
Company company = contract.getCompany();
if (company == null) {
holder.warn("合同未关联公司");
valid = false;
}
CompanyCustomer companyCustomer = getCompanyCustomerService().findByCompany(company);
if (companyCustomer == null) {
holder.warn("合同未关联客户");
valid = false;
} else {
if (!StringUtils.hasText(companyCustomer.getPath())) {
holder.warn("客户未设置文件夹");
valid = false;
}
LocalDate developDate = companyCustomer.getDevelopDate();
if (developDate == null) {
holder.warn("客户未设置开发日期");
valid = false;
}
if (!verifyCustomerFileByContract(companyCustomer, contract, holder)) {
valid = false;
}
}
return valid;
}
private boolean verifyCustomerFileByContract(CompanyCustomer companyCustomer, Contract contract,
MessageHolder holder) {
List<LocalDate> verifyDates = new ArrayList<>();
LocalDate minDate = LocalDate.of(2022, 1, 1);
LocalDate developDate = companyCustomer.getDevelopDate();
if (developDate != null) {
if (developDate.isAfter(minDate)) {
minDate = developDate;
}
}
if (contract.getSetupDate() != null) {
LocalDate setupDate = contract.getSetupDate();
if (setupDate.isBefore(developDate)) {
holder.error("合同提交日期 " + setupDate + " 早于客户开发日期 " + developDate + ".");
return false;
}
if (setupDate.isBefore(minDate)) {
holder.debug("合同提交日期 " + setupDate + " 早于 " + minDate + ", 跳过");
} else {
verifyDates.add(setupDate);
}
}
if (contract.getStartDate() != null) {
LocalDate startDate = contract.getStartDate();
if (startDate.isBefore(developDate)) {
holder.warn("合同起始日期 " + startDate + " 早于客户开发日期 " + developDate + ".");
}
if (startDate.isBefore(minDate)) {
holder.debug("合同起始日期 " + startDate + " 早于 " + minDate + ", 跳过");
} else {
verifyDates.add(startDate);
}
}
if (contract.getOrderDate() != null) {
LocalDate orderDate = contract.getOrderDate();
if (orderDate.isBefore(developDate)) {
holder.error("合同签订日期 " + orderDate + " 早于客户开发日期 " + developDate + ".");
return false;
}
if (orderDate.isBefore(minDate)) {
holder.debug("合同签订日期 " + orderDate + " 早于 " + minDate + ", 跳过");
} else {
verifyDates.add(orderDate);
}
}
if (verifyDates.isEmpty()) {
holder.warn("合同没有符合可核验的日期");
return false;
}
// 客户
List<CompanyCustomerFile> files = getCompanyCustomerFileService().findAllByCustomer(companyCustomer);
if (files == null || files.isEmpty()) {
holder.warn("未见客户评估表");
return false;
}
for (LocalDate verifyDate : verifyDates) {
CompanyCustomerFile customerFile = files.stream()
.filter(v -> v.getSignDate() != null && v.isValid())
.filter(v -> v.getType() == CompanyCustomerFileType.EvaluationForm)
.filter(v -> MyDateTimeUtils.dateValidFilter(verifyDate, v.getSignDate(),
v.getSignDate().plusYears(1), 7))
.findFirst().orElse(null);
if (customerFile != null) {
return true;
}
}
CompanyCustomerFile latestFile = files.stream()
.filter(v -> v.getSignDate() != null && v.isValid())
.filter(v -> v.getType() == CompanyCustomerFileType.EvaluationForm)
.max(Comparator.comparing(CompanyCustomerFile::getSignDate))
.orElse(null);
if (latestFile == null) {
holder.error("未匹配的客户评估");
return false;
}
holder.error("客户评估已过期,最后一个客户评估报告日期:" + latestFile.getSignDate() + ", 检测日期:"
+ verifyDates.stream().map(LocalDate::toString).collect(Collectors.joining(", ")));
return false;
}
private void verifyProject(Contract contract, Project project, MessageHolder holder) {
ProjectSaleType saleType = project.getSaleType();
if (saleType == null) {
String code = contract.getCode();
if (code != null && code.length() > 5) {
saleType = getSaleTypeService().findByCode(code.substring(0, 1));
}
}
if (saleType == null) {
holder.warn("销售类型未设置");
}
if (project.getAmount() == null || project.getAmount() <= 0) {
holder.error("金额小于等于0");
}
//
boolean needImport = false;
ProjectCost autoCost = getProjectCostService().findAutoCostByProject(project);
if (autoCost == null) {
// 创建 V0 项目成本
ProjectCost cost = getProjectCostService().newInstanceByProject(project);
cost.setVersion(0);
cost.setApplicant(getEmployeeService().findById(EmployeeService.DEFAULT_SYSTEM_EMPLOYEE_ID));
cost.setApplyTime(LocalDateTime.now());
cost.setDescription("自动导入");
autoCost = getProjectCostService().save(cost);
needImport = true;
} else {
// 检查 V0 项目成本
if (autoCost.getGrossProfitMargin() <= 0) {
NumberFormat instance = NumberFormat.getNumberInstance(getLocale());
instance.setMaximumFractionDigits(2);
NumberStringConverter converter = new NumberStringConverter(instance);
holder.warn("V0项目成本毛利率异常" + converter.toString(autoCost.getGrossProfitMargin()) + "<=0%");
needImport = true;
}
}
if (needImport && !autoCost.isImportLock()) {
ProjectCostImportItemsFromContractsTasker tasker = new ProjectCostImportItemsFromContractsTasker();
tasker.setCost(autoCost);
// 在类中添加以下依赖,假设使用 Spring Security 来获取当前登录用户
// 以下代码替换原有的获取当前用户逻辑,假设用户名即为员工 ID
// 需根据实际业务调整 UserDetails 中的信息获取方式
tasker.setCurrentUser(() -> {
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
String username;
if (principal instanceof UserDetails) {
username = ((UserDetails) principal).getUsername();
} else {
username = principal.toString();
}
try {
return getEmployeeService().findByName(username);
} catch (NumberFormatException e) {
// 处理转换失败的情况,可根据实际需求调整
return null;
}
});
autoCost.setApplyTime(LocalDateTime.now());
holder.debug("更新V0项目成本");
SpringApp.getTaskMonitorCenter().registerAndStartTask(tasker);
}
// 检查最新的项目成本,默认 V1
ProjectCost latestCost = getProjectCostService().findLatestByProject(project);
if (latestCost == null) {
ProjectCost cost = getProjectCostService().newInstanceByProject(project);
cost.setVersion(1);
Employee applicant = project.getApplicant();
if (applicant == null) {
applicant = contract.getEmployee();
}
cost.setApplicant(applicant);
cost.setApplyTime(project.getCreated().atTime(LocalTime.now()));
latestCost = getProjectCostService().save(cost);
} else {
//
if (latestCost.getGrossProfitMargin() <= 0) {
NumberFormat instance = NumberFormat.getNumberInstance(getLocale());
instance.setMaximumFractionDigits(2);
NumberStringConverter converter = new NumberStringConverter(instance);
holder.warn("V" + latestCost.getVersion() + "项目成本毛利率异常:"
+ converter.toString(latestCost.getGrossProfitMargin()) + "<=0%");
} else if (latestCost.getGrossProfitMargin() >= 50) {
NumberFormat instance = NumberFormat.getNumberInstance(getLocale());
instance.setMaximumFractionDigits(2);
NumberStringConverter converter = new NumberStringConverter(instance);
holder.warn("V" + latestCost.getVersion() + "项目成本毛利率异常:"
+ converter.toString(latestCost.getGrossProfitMargin()) + ">=50%");
}
}
if (project.isUseBid()) {
List<ProjectBid> bids = getProjectBidService().findAllByProject(project);
if (bids.isEmpty()) {
holder.warn("投标未创建");
}
}
if (project.isUseOffer()) {
List<ProjectQuotation> quotations = getProjectQuotationService().findAllByProject(project);
if (quotations.isEmpty()) {
holder.warn("报价未创建");
}
}
}
private boolean verifyContractFileAsCustomer(Project project, Contract contract, MessageHolder holder) {
boolean loseFile = false;
List<ContractFile> files = getContractFileService().findAllByContract(contract);
if (project != null) {
// 投标
if (project.isUseBid()) {
// 投标审批表
if (!hasFileType(files, ContractFileType.BidApprovalForm)) {
holder.error(getFileTypeLocalValue(ContractFileType.BidApprovalForm) + "未上传");
loseFile = true;
}
// 中标通知书
if (!hasFileType(files, ContractFileType.BidAcceptanceLetter)) {
holder.error(getFileTypeLocalValue(ContractFileType.BidAcceptanceLetter) + "未上传");
loseFile = true;
}
}
// 报价
if (project.isUseOffer()) {
if (!hasFileType(files, ContractFileType.QuotationApprovalForm)) {
holder.error(getFileTypeLocalValue(ContractFileType.QuotationApprovalForm) + "未上传");
loseFile = true;
}
}
ProjectSaleType saleType = project.getSaleType();
if (saleType != null) {
List<ProjectSaleTypeRequireFileType> list = getSaleTypeRequireFileTypeService()
.findBySaleTypeId(saleType.getId());
for (ProjectSaleTypeRequireFileType item : list) {
ContractFileType fileType = item.getFileType();
if (fileType != null) {
if (!hasFileType(files, fileType)) {
holder.error(getFileTypeLocalValue(fileType) + "未上传");
loseFile = true;
}
}
}
if (!Hibernate.isInitialized(saleType)) {
saleType = getSaleTypeService().findById(saleType.getId());
}
if (saleType.isCriticalProjectDecision()) {
if (contract.getAmount() != null && contract.getAmount() >= saleType.getCriticalProjectLimit()) {
holder.debug("合同金额 " + contract.getAmount() + " 超过 " + saleType.getCriticalProjectLimit());
if (!hasFileType(files, ContractFileType.CriticalProjectDecisionRecord)) {
holder.error(getFileTypeLocalValue(ContractFileType.CriticalProjectDecisionRecord) + "未上传");
loseFile = true;
}
}
}
}
}
if (loseFile && files.isEmpty()) {
holder.warn("!上传文件空!");
}
return !loseFile;
}
}

View File

@@ -0,0 +1,61 @@
package com.ecep.contract.ds.contract.tasker;
import java.util.Locale;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Level;
import com.ecep.contract.MessageHolder;
import com.ecep.contract.ds.contract.service.ContractService;
import com.ecep.contract.model.Contract;
import com.ecep.contract.ui.Tasker;
import lombok.Getter;
import lombok.Setter;
public class ContractVerifyTasker extends Tasker<Object> {
@Getter
@Setter
private Contract contract;
ContractVerifyComm comm = new ContractVerifyComm();
AtomicBoolean verified = new AtomicBoolean(true);
@Override
public Object call() throws Exception {
updateTitle("验证合同 " + contract.getCode() + " 及其子合同是否符合合规要求");
return execute(new MessageHolderImpl() {
@Override
public void addMessage(Level level, String message) {
super.addMessage(level, message);
if (level.intValue() > Level.INFO.intValue()) {
verified.set(false);
}
}
});
}
@Override
protected Object execute(MessageHolder holder) {
comm.verify(contract, holder);
if (verified.get()) {
updateMessage(Level.CONFIG, "合规验证通过");
} else {
updateMessage(Level.SEVERE, "合规验证不通过");
}
return null;
}
public void setContractService(ContractService contractService) {
comm.setContractService(contractService);
}
public Locale getLocale() {
return comm.getLocale();
}
public void setLocale(Locale locale) {
comm.setLocale(locale);
}
}

View File

@@ -0,0 +1,363 @@
package com.ecep.contract.ds.contract.tasker;
import static com.ecep.contract.util.ExcelUtils.setCellValue;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.time.LocalDate;
import java.util.List;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.hibernate.Hibernate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;
import com.ecep.contract.MessageHolder;
import com.ecep.contract.SpringApp;
import com.ecep.contract.ds.project.service.DeliverySignMethodService;
import com.ecep.contract.ds.project.service.ProductTypeService;
import com.ecep.contract.ds.project.service.ProjectCostItemService;
import com.ecep.contract.ds.project.service.ProjectCostService;
import com.ecep.contract.ds.project.service.ProjectIndustryService;
import com.ecep.contract.ds.project.service.ProjectService;
import com.ecep.contract.ds.project.service.ProjectTypeService;
import com.ecep.contract.ds.project.service.SaleTypeService;
import com.ecep.contract.model.Company;
import com.ecep.contract.model.Contract;
import com.ecep.contract.model.Employee;
import com.ecep.contract.model.ProductType;
import com.ecep.contract.model.Project;
import com.ecep.contract.model.ProjectCost;
import com.ecep.contract.model.ProjectCostItem;
import com.ecep.contract.model.ProjectIndustry;
import com.ecep.contract.model.ProjectSaleType;
import com.ecep.contract.model.ProjectType;
import com.ecep.contract.ui.Tasker;
import lombok.Getter;
import lombok.Setter;
/**
* 合同成本审批表更新任务
* 成本审批表为Excel文件默认更新 #matchedSheetName成本 sheet如果没有匹配名称的sheet则尝试使用第一个sheet
*
*/
public class CustomerContractCostFormUpdateTask extends Tasker<Object> {
private static final Logger logger = LoggerFactory.getLogger(CustomerContractCostFormUpdateTask.class);
/**
* 对应的合同
*/
@Getter
@Setter
private Contract contract;
/**
* 成本表文件名
*/
@Setter
private String fileName;
/**
* 模板文件名
*/
@Setter
private String template;
/**
* 填写日期
*/
@Setter
private LocalDate applyDate;
/**
* 目标文件
*/
private File destFile;
/**
* 用于匹配成本审批表的Sheet名字第一包含字符的sheet为要更新的sheet
*/
@Setter
private String matchedSheetName = "成本";
@Setter
private ProjectService projectService;
@Setter
private ProjectTypeService projectTypeService;
@Setter
private SaleTypeService saleTypeService;
@Setter
private ProjectIndustryService projectIndustryService;
@Setter
private ProductTypeService productTypeService;
@Setter
private DeliverySignMethodService deliverySignMethodService;
@Setter
private ProjectCostService costService;
@Setter
private ProjectCostItemService costItemService;
private ProjectService getProjectService() {
if (projectService == null) {
projectService = SpringApp.getBean(ProjectService.class);
}
return projectService;
}
private ProjectTypeService getProjectTypeService() {
if (projectTypeService == null) {
projectTypeService = SpringApp.getBean(ProjectTypeService.class);
}
return projectTypeService;
}
private SaleTypeService getSaleTypeService() {
if (saleTypeService == null) {
saleTypeService = SpringApp.getBean(SaleTypeService.class);
}
return saleTypeService;
}
private ProjectIndustryService getProjectIndustryService() {
if (projectIndustryService == null) {
projectIndustryService = SpringApp.getBean(ProjectIndustryService.class);
}
return projectIndustryService;
}
private ProductTypeService getProductTypeService() {
if (productTypeService == null) {
productTypeService = SpringApp.getBean(ProductTypeService.class);
}
return productTypeService;
}
private DeliverySignMethodService getDeliverySignMethodService() {
if (deliverySignMethodService == null) {
deliverySignMethodService = SpringApp.getBean(DeliverySignMethodService.class);
}
return deliverySignMethodService;
}
private ProjectCostService getCostService() {
if (costService == null) {
costService = SpringApp.getBean(ProjectCostService.class);
}
return costService;
}
private ProjectCostItemService getCostItemService() {
if (costItemService == null) {
costItemService = SpringApp.getBean(ProjectCostItemService.class);
}
return costItemService;
}
@Override
protected Object execute(MessageHolder holder) throws Exception {
updateCostForm(holder);
return null;
}
private void updateCostForm(MessageHolder holder) {
if (!StringUtils.hasText(contract.getPath())) {
holder.error("供应商目录未设置,请先设置供应商目录");
return;
}
File templateFile = new File(template);
if (!templateFile.exists()) {
holder.warn("评价表模板文件 " + templateFile.getAbsolutePath() + " 不存在,请检查");
return;
}
String template_file_name = templateFile.getName();
File dir = new File(contract.getPath());
destFile = new File(dir, fileName);
if (destFile.exists()) {
holder.debug("表单文件已经存在,尝试更新...");
try (
InputStream inp = new FileInputStream(destFile);
Workbook wb = WorkbookFactory.create(inp)
) {
updateCustomerContractCost(wb, holder);
holder.info(fileName + "已更新");
} catch (Exception e) {
holder.error(e.getMessage());
logger.error(e.getMessage(), e);
}
} else {
holder.debug("根据模板 " + template_file_name + " 创建表单 " + destFile.getName());
try (
InputStream inp = new FileInputStream(template);
Workbook wb = WorkbookFactory.create(inp)
) {
updateCustomerContractCost(wb, holder);
holder.info(fileName + "已更新");
} catch (Exception e) {
holder.error(e.getMessage());
logger.error(e.getMessage(), e);
}
}
}
private void updateCustomerContractCost(
Workbook wb,
MessageHolder holder) throws IOException {
Sheet sheet = null;
if (StringUtils.hasText(matchedSheetName)) {
for (Sheet v : wb) {
if (v.getSheetName().contains(matchedSheetName)) {
sheet = v;
break;
}
}
if (sheet == null) {
holder.error("检查模板文件,找不到成本页");
return;
}
} else {
sheet = wb.getSheetAt(0);
}
updateCustomerContractCost(sheet);
// 输出到文件
try (OutputStream fileOut = new FileOutputStream(destFile)) {
wb.write(fileOut);
} catch (FileNotFoundException e) {
holder.error("写文件时发生错误:" + e.getMessage());
logger.error(e.getMessage(), e);
}
}
private void updateCustomerContractCost(Sheet sheet) {
// 项目名
String projectName = contract.getName();
Project project = contract.getProject();
//销售类型
ProjectSaleType saleType = null;
// 项目类型
ProjectType projectType = null;
// 使用场所
ProjectIndustry industry = null;
// 销售类别
ProductType productType = null;
// 项目地址
String address = null;
if (project != null) {
if (!Hibernate.isInitialized(project)) {
project = getProjectService().findById(project.getId());
contract.setProject(project);
}
projectName = project.getName();
saleType = project.getSaleType();
if (saleType != null) {
if (!Hibernate.isInitialized(saleType)) {
saleType = getSaleTypeService().findById(saleType.getId());
project.setSaleType(saleType);
}
}
projectType = project.getProjectType();
if (projectType != null) {
if (!Hibernate.isInitialized(projectType)) {
projectType = getProjectTypeService().findById(projectType.getId());
project.setProjectType(projectType);
}
}
industry = project.getIndustry();
if (industry != null) {
if (!Hibernate.isInitialized(industry)) {
industry = getProjectIndustryService().findById(industry.getId());
project.setIndustry(industry);
}
}
productType = project.getProductType();
if (productType != null) {
if (!Hibernate.isInitialized(productType)) {
productType = getProductTypeService().findById(productType.getId());
project.setProductType(productType);
}
}
address = project.getAddress();
}
// 项目名称
setCellValue(sheet, "C5", projectName);
setCellValue(sheet, "M5", saleType == null ? "" : saleType.getName());
setCellValue(sheet, "I5", projectType == null ? "" : projectType.getName());
setCellValue(sheet, "M6", industry == null ? "" : industry.getName());
setCellValue(sheet, "I6", productType == null ? "" : productType.getName());
setCellValue(sheet, "C7", address);
// 买方
Company company = contract.getCompany();
if (company != null) {
if (!Hibernate.isInitialized(company)) {
company = getCompanyService().findById(company.getId());
contract.setCompany(company);
}
setCellValue(sheet, "C6", company.getName());
}
// 销售员
Employee employee = contract.getEmployee();
if (employee != null) {
if (!Hibernate.isInitialized(employee)) {
employee = getEmployeeService().findById(employee.getId());
contract.setEmployee(employee);
}
setCellValue(sheet, "M7", employee.getName());
}
float taxAndSurcharges = 11;
ProjectCost cost = getCostService().findByContract(contract);
if (cost != null) {
taxAndSurcharges = cost.getTaxAndSurcharges();
if (cost.getApplyTime() != null) {
applyDate = cost.getApplyTime().toLocalDate();
}
}
setCellValue(sheet, "D40", taxAndSurcharges + "%");
float stampTax = 0.03f;
setCellValue(sheet, "D39", stampTax + "%");
List<ProjectCostItem> items = getCostItemService().findByCost(cost);
for (int i = 0; i < items.size(); i++) {
ProjectCostItem item = items.get(i);
int row = 10 + i;
setCellValue(sheet, row, 0, item.getTitle());
setCellValue(sheet, row, 2, item.getSpecification());
setCellValue(sheet, row, 3, item.getInQuantity());
setCellValue(sheet, row, 4, item.getOutExclusiveTaxPrice());
setCellValue(sheet, row, 6, item.getOutTaxRate() / 100);
setCellValue(sheet, row, 8, item.getInExclusiveTaxPrice());
setCellValue(sheet, row, 10, item.getInTaxRate() / 100);
}
if (applyDate != null) {
setCellValue(sheet, "I7", applyDate);
}
}
}

View File

@@ -0,0 +1,41 @@
package com.ecep.contract.ds.customer;
import java.util.function.Function;
import org.hibernate.Hibernate;
import com.ecep.contract.model.CustomerCatalog;
import com.ecep.contract.util.EntityStringConverter;
public class CustomerClassStringConverter extends EntityStringConverter<CustomerCatalog> {
private Function<CustomerCatalog, CustomerCatalog> initialized;
private Function<String, CustomerCatalog> fromString;
@Override
public String toString(CustomerCatalog cc) {
if (cc == null) {
return "-";
}
if (initialized != null && !Hibernate.isInitialized(cc)) {
cc = initialized.apply(cc);
}
return cc.getCode() + " " + cc.getName();
}
@Override
public CustomerCatalog fromString(String string) {
if (fromString == null) {
return null;
}
return fromString.apply(string);
}
public void setFromString(Function<String, CustomerCatalog> fromString) {
this.fromString = fromString;
}
public void setInitialized(Function<CustomerCatalog, CustomerCatalog> initialized) {
this.initialized = initialized;
}
}

View File

@@ -0,0 +1,35 @@
select *, PATH, replace(PATH, '\\测试文件夹\\0-资信评估\\', '\\A-客户资信\\') as NEW_PATH
from COMPANY_CUSTOMER
where PATH like '%\\\\测试文件夹\\\\0-资信评估\\\\%';
update COMPANY_CUSTOMER
set PATH = replace(PATH, '\\测试文件夹\\0-资信评估\\', '\\A-客户资信\\')
where PATH like '%\\\\测试文件夹\\\\0-资信评估\\\\%';
update COMPANY_CUSTOMER_FILE
set FILE_PATH = replace(FILE_PATH, '\\测试文件夹\\0-资信评估\\', '\\A-客户资信\\')
where FILE_PATH like '%\\\\测试文件夹\\\\0-资信评估\\\\%';
update COMPANY_CUSTOMER_FILE
set EDIT_FILE_PATH = replace(EDIT_FILE_PATH, '\\测试文件夹\\0-资信评估\\', '\\A-客户资信\\')
where EDIT_FILE_PATH like '%\\\\测试文件夹\\\\0-资信评估\\\\%';
SELECT CC.ID, c.NAME, CCE.DEV_DATE, T1.*
from COMPANY_CUSTOMER CC
left join (
select CUSTOMER_ID,SIGN_DATE,LEVEL, CREDIT_LEVEL from COMPANY_CUSTOMER_FILE left join COMPANY_CUSTOMER_EVALUATION_FORM_FILE on COMPANY_CUSTOMER_FILE.ID = COMPANY_CUSTOMER_EVALUATION_FORM_FILE.ID
where TYPE = 'EvaluationForm' and VALID=true
) as T1 on T1.CUSTOMER_ID = CC.ID
left join COMPANY_CUSTOMER_ENTITY CCE on CC.ID = CCE.COMPANY_CUSTOMER_ID
left join COMPANY c on CC.COMPANY_ID = c.ID
order by DEV_DATE desc;

View File

@@ -0,0 +1,18 @@
package com.ecep.contract.ds.customer.repository;
import java.util.List;
import java.util.Optional;
import org.springframework.stereotype.Repository;
import com.ecep.contract.ds.MyRepository;
import com.ecep.contract.model.CompanyCustomer;
import com.ecep.contract.model.CompanyCustomerEntity;
@Repository
public interface CompanyCustomerEntityRepository extends MyRepository<CompanyCustomerEntity, Integer>
{
Optional<CompanyCustomerEntity> findByCode(String code);
List<CompanyCustomerEntity> findByCustomer(CompanyCustomer customer);
}

View File

@@ -0,0 +1,22 @@
package com.ecep.contract.ds.customer.repository;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import com.ecep.contract.model.CompanyCustomer;
import com.ecep.contract.model.CompanyCustomerEvaluationFormFile;
@Repository
public interface CompanyCustomerEvaluationFormFileRepository extends JpaRepository<CompanyCustomerEvaluationFormFile, Integer>, JpaSpecificationExecutor<CompanyCustomerEvaluationFormFile> {
List<CompanyCustomerEvaluationFormFile> findAllByCustomerFileCustomer(@Param("customer") CompanyCustomer customer);
@Query(value = "SELECT * FROM COMPANY_CUSTOMER_FILE ccf left join COMPANY_CUSTOMER_EVALUATION_FORM_FILE CCEFF on ccf.ID = CCEFF.ID " +
"where ccf.CUSTOMER_ID=:customer and ccf.TYPE=:fileType", nativeQuery = true)
List<CompanyCustomerEvaluationFormFile> findAllByCustomerAndType(@Param("customer") int companyCustomerId, @Param("fileType") String type);
}

View File

@@ -0,0 +1,18 @@
package com.ecep.contract.ds.customer.repository;
import java.util.List;
import org.springframework.stereotype.Repository;
import com.ecep.contract.CompanyCustomerFileType;
import com.ecep.contract.ds.MyRepository;
import com.ecep.contract.model.CompanyCustomer;
import com.ecep.contract.model.CompanyCustomerFile;
@Repository
public interface CompanyCustomerFileRepository extends MyRepository<CompanyCustomerFile, Integer> {
List<CompanyCustomerFile> findAllByCustomer(CompanyCustomer companyCustomer);
List<CompanyCustomerFile> findAllByCustomerAndType(CompanyCustomer customer, CompanyCustomerFileType type);
}

View File

@@ -0,0 +1,22 @@
package com.ecep.contract.ds.customer.repository;
import org.springframework.stereotype.Repository;
import com.ecep.contract.CompanyCustomerFileType;
import com.ecep.contract.ds.other.repository.BaseEnumEntityRepository;
import com.ecep.contract.model.CompanyCustomerFileTypeLocal;
@Repository
public interface CompanyCustomerFileTypeLocalRepository
extends BaseEnumEntityRepository<CompanyCustomerFileType, CompanyCustomerFileTypeLocal, Integer> {
@Override
default CompanyCustomerFileType[] getEnumConstants() {
return CompanyCustomerFileType.values();
}
@Override
default CompanyCustomerFileTypeLocal newEntity() {
return new CompanyCustomerFileTypeLocal();
}
}

View File

@@ -0,0 +1,21 @@
package com.ecep.contract.ds.customer.repository;
import java.util.Optional;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import com.ecep.contract.ds.MyRepository;
import com.ecep.contract.model.Company;
import com.ecep.contract.model.CompanyCustomer;
@Repository
public interface CompanyCustomerRepository extends MyRepository<CompanyCustomer, Integer> {
Optional<CompanyCustomer> findByCompany(Company company);
@Modifying
@Transactional
int deleteAllByCompany(Company company);
}

View File

@@ -0,0 +1,16 @@
package com.ecep.contract.ds.customer.repository;
import java.util.Optional;
import org.springframework.data.repository.ListCrudRepository;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.stereotype.Repository;
import com.ecep.contract.model.CustomerCatalog;
@Repository
public interface CustomerCatalogRepository extends
// JDBC interfaces
ListCrudRepository<CustomerCatalog, Integer>, PagingAndSortingRepository<CustomerCatalog, Integer> {
Optional<CustomerCatalog> findByCode(String code);
}

View File

@@ -0,0 +1,99 @@
package com.ecep.contract.ds.customer.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import com.ecep.contract.IEntityService;
import com.ecep.contract.ds.customer.repository.CompanyCustomerEntityRepository;
import com.ecep.contract.model.CompanyCustomer;
import com.ecep.contract.model.CompanyCustomerEntity;
import com.ecep.contract.util.SpecificationUtils;
@Lazy
@Service
@CacheConfig(cacheNames = "company-customer-entity")
public class CompanyCustomerEntityService implements IEntityService<CompanyCustomerEntity> {
@Lazy
@Autowired
private CompanyCustomerEntityRepository repository;
@Cacheable(key = "#p0")
@Override
public CompanyCustomerEntity findById(Integer id) {
return repository.findById(id).orElse(null);
}
@Override
public Specification<CompanyCustomerEntity> getSpecification(String searchText) {
if (!StringUtils.hasText(searchText)) {
return null;
}
return SpecificationUtils.andWith(searchText, this::buildSearchSpecification);
}
protected Specification<CompanyCustomerEntity> buildSearchSpecification(String searchText) {
return (root, query, builder) -> {
return builder.or(
builder.like(root.get("name"), "%" + searchText + "%"),
builder.like(root.get("abbName"), "%" + searchText + "%"),
builder.like(root.get("code"), "%" + searchText + "%"));
};
}
public List<CompanyCustomerEntity> search(String searchText) {
Specification<CompanyCustomerEntity> spec = getSpecification(searchText);
return repository.findAll(spec, Pageable.ofSize(10)).getContent();
}
@Override
public Page<CompanyCustomerEntity> findAll(Specification<CompanyCustomerEntity> spec, Pageable pageable) {
return repository.findAll(spec, pageable);
}
@Caching(evict = {
@CacheEvict(key = "#p0.id"),
@CacheEvict(key = "'code-'+#p0.code")
})
@Override
public void delete(CompanyCustomerEntity entity) {
repository.delete(entity);
}
@Caching(evict = {
@CacheEvict(key = "#p0.id"),
@CacheEvict(key = "'code-'+#p0.code")
})
@Override
public CompanyCustomerEntity save(CompanyCustomerEntity entity) {
return repository.save(entity);
}
public List<CompanyCustomerEntity> findAllByCustomer(CompanyCustomer companyCustomer) {
return repository.findByCustomer(companyCustomer);
}
@Cacheable(key = "'code-'+#p0")
public CompanyCustomerEntity findByCustomerCode(String customerCode) {
return repository.findByCode(customerCode).orElse(null);
}
public void resetTo(CompanyCustomer from, CompanyCustomer to) {
List<CompanyCustomerEntity> entities = repository.findByCustomer(from);
for (CompanyCustomerEntity entity : entities) {
entity.setCustomer(to);
}
repository.saveAll(entities);
}
}

View File

@@ -0,0 +1,255 @@
package com.ecep.contract.ds.customer.service;
import java.io.File;
import java.time.LocalDate;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.function.Consumer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import com.ecep.contract.CompanyCustomerFileType;
import com.ecep.contract.IEntityService;
import com.ecep.contract.SpringApp;
import com.ecep.contract.ds.company.service.CompanyBasicService;
import com.ecep.contract.ds.contract.service.ContractService;
import com.ecep.contract.ds.customer.repository.CompanyCustomerEvaluationFormFileRepository;
import com.ecep.contract.ds.customer.repository.CompanyCustomerFileRepository;
import com.ecep.contract.ds.other.service.SysConfService;
import com.ecep.contract.model.CompanyCustomer;
import com.ecep.contract.model.CompanyCustomerEvaluationFormFile;
import com.ecep.contract.model.CompanyCustomerFile;
import com.ecep.contract.model.Contract;
import jakarta.persistence.criteria.Path;
@Lazy
@Service
@CacheConfig(cacheNames = "company-customer-file")
public class CompanyCustomerFileService implements IEntityService<CompanyCustomerFile> {
private static final Logger logger = LoggerFactory.getLogger(CompanyCustomerFileService.class);
/**
* 客户资信评估表
*/
public static final String KEY_EVALUATION_FORM_TEMPLATE = "customer.evaluation.form.template";
@Lazy
@Autowired
private SysConfService confService;
@Lazy
@Autowired
private CompanyCustomerFileRepository companyCustomerFileRepository;
@Lazy
@Autowired
private CompanyCustomerEvaluationFormFileRepository companyCustomerEvaluationFormFileRepository;
@Cacheable(key = "#p0")
public CompanyCustomerFile findById(Integer id) {
return companyCustomerFileRepository.findById(id).orElse(null);
}
@Override
public Specification<CompanyCustomerFile> getSpecification(String searchText) {
return (root, query, builder) -> {
return builder.or(builder.like(root.get("filePath"), "%" + searchText + "%"));
};
}
@Caching(
evict = {
@CacheEvict(key = "#p0.id"),
}
)
public void delete(CompanyCustomerFile file) {
if (file.getType() == CompanyCustomerFileType.EvaluationForm) {
companyCustomerEvaluationFormFileRepository.deleteById(file.getId());
}
companyCustomerFileRepository.delete(file);
}
@Caching(
evict = {
@CacheEvict(key = "#p0.id"),
}
)
public CompanyCustomerFile save(CompanyCustomerFile dbFile) {
return companyCustomerFileRepository.save(dbFile);
}
public CompanyCustomerEvaluationFormFile save(CompanyCustomerEvaluationFormFile formFile) {
return companyCustomerEvaluationFormFileRepository.save(formFile);
}
@Override
public Page<CompanyCustomerFile> findAll(Specification<CompanyCustomerFile> spec, Pageable pageable) {
return companyCustomerFileRepository.findAll(spec, pageable);
}
public List<CompanyCustomerFile> findAllByCustomer(CompanyCustomer customer) {
return companyCustomerFileRepository.findAllByCustomer(customer);
}
public void deleteById(int id) {
Optional<CompanyCustomerFile> optional = companyCustomerFileRepository.findById(id);
if (optional.isEmpty()) {
return;
}
CompanyCustomerFile customerFile = optional.get();
if (customerFile.getType() == CompanyCustomerFileType.EvaluationForm) {
companyCustomerEvaluationFormFileRepository.deleteById(id);
}
companyCustomerFileRepository.delete(customerFile);
}
public List<CompanyCustomerFile> findAll(Specification<CompanyCustomerFile> spec, Sort sort) {
return companyCustomerFileRepository.findAll(spec, sort);
}
public List<CompanyCustomerFile> saveAll(List<CompanyCustomerFile> files) {
return companyCustomerFileRepository.saveAll(files);
}
public List<CompanyCustomerFile> findAllByCustomerAndType(CompanyCustomer customer, CompanyCustomerFileType type) {
return companyCustomerFileRepository.findAllByCustomerAndType(customer, type);
}
public List<CompanyCustomerEvaluationFormFile> findAllCustomerEvaluationFormFiles(CompanyCustomer companyCustomer) {
return findAllByCustomerAndType(companyCustomer, CompanyCustomerFileType.EvaluationForm).stream().map(v -> {
return companyCustomerEvaluationFormFileRepository.findById(v.getId()).orElseGet(() -> {
CompanyCustomerEvaluationFormFile formFile = new CompanyCustomerEvaluationFormFile();
formFile.setCustomerFile(v);
formFile.setId(v.getId());
return companyCustomerEvaluationFormFileRepository.save(formFile);
});
}).toList();
}
public CompanyCustomerEvaluationFormFile findCustomerEvaluationFormFileById(int id) {
return companyCustomerEvaluationFormFileRepository.findById(id).orElse(null);
}
public CompanyCustomerEvaluationFormFile findCustomerEvaluationFormFileByCustomerFile(CompanyCustomerFile customerFile) {
Integer id = customerFile.getId();
if (id == null) {
CompanyCustomerFile saved = companyCustomerFileRepository.save(customerFile);
id = saved.getId();
customerFile.setId(id);
}
CompanyCustomerEvaluationFormFile formFile = companyCustomerEvaluationFormFileRepository.findById(id).orElse(null);
if (formFile == null) {
formFile = new CompanyCustomerEvaluationFormFile();
formFile.setId(id);
formFile.setCustomerFile(customerFile);
companyCustomerEvaluationFormFileRepository.save(formFile);
}
return formFile;
}
public LocalDate getNextSignDate(CompanyCustomer companyCustomer, Consumer<String> state) {
LocalDate miniContractDate = LocalDate.of(2022, 1, 1);
// 检索全部合同
ContractService contractService = SpringApp.getBean(ContractService.class);
List<Contract> contractList = contractService.findAllByCompanyCustomer(companyCustomer, null, null);
if (contractList.isEmpty()) {
state.accept("未发现已登记的合同");
return null;
}
// 检索评估表
List<CompanyCustomerFile> files = findAllByCustomerAndType(companyCustomer, CompanyCustomerFileType.EvaluationForm);
CompanyCustomerFile latestFile = files.stream()
.filter(v -> v.getSignDate() != null && v.isValid())
.max(Comparator.comparing(CompanyCustomerFile::getSignDate))
.orElse(null);
// 没有有效的评估表的评价日期
if (latestFile == null) {
state.accept("未发现有效的评估表");
// 返回最早的合同日期
Contract firstContract = contractList.stream()
.filter(v -> v.getSetupDate() != null && !v.getSetupDate().isBefore(miniContractDate))
.min(Comparator.comparing(Contract::getSetupDate))
.orElse(null);
if (firstContract == null) {
state.accept("最早的合同不存在?");
return null;
}
LocalDate setupDate = firstContract.getSetupDate();
state.accept("依据合同 " + firstContract.getCode() + " 的日期 " + setupDate + " 推算");
return CompanyBasicService.adjustToWorkDay(setupDate.plusDays(-7));
}
// 检查失效日期起的第一个合同
LocalDate nextInValidDate = latestFile.getSignDate().plusYears(1);
File file = new File(latestFile.getFilePath());
state.accept("依据 " + file.getName() + " 的失效期 " + nextInValidDate + " 检索合同");
List<Contract> matchedContracts = contractList.stream()
.filter(v -> v.getSetupDate().isAfter(nextInValidDate)).toList();
// 没有在失效日期后的合同时,使用失效日期
if (matchedContracts.isEmpty()) {
state.accept("未发现失效期 " + nextInValidDate + " 后的合同");
return null;
}
state.accept("发现匹配合同 " + matchedContracts.size() + "");
// 按时间取最早一个
Contract firstContract = matchedContracts.stream()
.min(Comparator.comparing(Contract::getSetupDate))
.orElse(null);
LocalDate setupDate = firstContract.getSetupDate();
state.accept("匹配失效期 " + nextInValidDate + " 后的第一个合同 " + firstContract.getCode());
state.accept("依据合同 " + firstContract.getCode() + " 的日期 " + setupDate + " 推算");
return CompanyBasicService.adjustToWorkDay(setupDate.plusDays(-7));
}
public File getEvaluationFormTemplate() {
String path = confService.getString(KEY_EVALUATION_FORM_TEMPLATE);
if (path == null) {
return null;
}
return new File(path);
}
/**
* 将指定源客户的文件记录转移到目标客户下。
*
* @param from 源客户对象,其关联的文件将被转移
* @param to 目标客户对象,将接收源客户的文件记录
*/
public void resetTo(CompanyCustomer from, CompanyCustomer to) {
List<CompanyCustomerFile> list = companyCustomerFileRepository.findAllByCustomer(from);
for (CompanyCustomerFile file : list) {
file.setCustomer(to);
}
companyCustomerFileRepository.saveAll(list);
}
public List<CompanyCustomerEvaluationFormFile> searchEvaluationFile(CompanyCustomer customer, String searchText) {
Specification<CompanyCustomerEvaluationFormFile> spec = (root, query, builder) -> {
Path<Object> customerFile = root.get("customerFile");
return builder.and(
builder.isNotNull(customerFile),
builder.equal(customerFile.get("customer"), customer),
builder.equal(customerFile.get("valid"), true),
builder.like(customerFile.get("filePath"), "%" + searchText + "%"));
};
return companyCustomerEvaluationFormFileRepository.findAll(spec, Pageable.ofSize(10)).getContent();
}
}

View File

@@ -0,0 +1,409 @@
package com.ecep.contract.ds.customer.service;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import com.ecep.contract.constant.CompanyCustomerConstant;
import com.ecep.contract.util.CompanyUtils;
import com.ecep.contract.util.FileUtils;
import org.hibernate.Hibernate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import com.ecep.contract.CompanyCustomerFileType;
import com.ecep.contract.IEntityService;
import com.ecep.contract.ds.company.CompanyFileUtils;
import com.ecep.contract.ds.company.service.CompanyBasicService;
import com.ecep.contract.ds.customer.repository.CompanyCustomerEvaluationFormFileRepository;
import com.ecep.contract.ds.customer.repository.CompanyCustomerRepository;
import com.ecep.contract.ds.customer.repository.CustomerCatalogRepository;
import com.ecep.contract.ds.other.service.SysConfService;
import com.ecep.contract.model.Company;
import com.ecep.contract.model.CompanyBasicFile;
import com.ecep.contract.model.CompanyCustomer;
import com.ecep.contract.model.CompanyCustomerEntity;
import com.ecep.contract.model.CompanyCustomerEvaluationFormFile;
import com.ecep.contract.model.CompanyCustomerFile;
import com.ecep.contract.model.CustomerCatalog;
import com.ecep.contract.util.MyStringUtils;
import com.ecep.contract.util.SpecificationUtils;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import jakarta.persistence.criteria.Path;
@Lazy
@Service
@CacheConfig(cacheNames = "company-customer")
public class CompanyCustomerService extends CompanyBasicService
implements IEntityService<CompanyCustomer> {
private static final Logger logger = LoggerFactory.getLogger(CompanyCustomerService.class);
public static final String KEY_BASE_PATH = "customer.base.path";
public static final String KEY_SALEBOOK_PATH = "customer.salebook.path";
@Lazy
@Autowired
private CompanyCustomerRepository companyCustomerRepository;
@Lazy
@Autowired
private CompanyCustomerFileService companyCustomerFileService;
@Lazy
@Autowired
private CompanyCustomerEvaluationFormFileRepository companyCustomerEvaluationFormFileRepository;
@Lazy
@Autowired
private SysConfService confService;
@Lazy
@Autowired
private CustomerCatalogRepository customerCatalogRepository;
@Lazy
@Autowired
private CompanyCustomerEntityService companyCustomerEntityService;
public CompanyCustomer findByCompany(Company company) {
return companyCustomerRepository.findByCompany(company).orElse(null);
}
@Cacheable(key = "#p0")
public CompanyCustomer findById(Integer id) {
return companyCustomerRepository.findById(id).orElse(null);
}
@Caching(evict = {
@CacheEvict(key = "#p0.id")
})
public CompanyCustomer save(CompanyCustomer companyCustomer) {
return companyCustomerRepository.save(companyCustomer);
}
@Caching(evict = {
@CacheEvict(key = "#p0")
})
@Override
public void delete(CompanyCustomer entity) {
companyCustomerRepository.delete(entity);
}
@Override
public Specification<CompanyCustomer> getSpecification(String searchText) {
if (!StringUtils.hasText(searchText)) {
return null;
}
Specification<CompanyCustomer> nameSpec = (root, query, builder) -> {
Path<Company> company = root.get("company");
return companyService.buildSearchPredicate(searchText, company, query, builder);
};
// 判断是否全是数字
if (MyStringUtils.isAllDigit(searchText)) {
// 全数字就按 Id 查询
try {
int id = Integer.parseInt(searchText);
Specification<CompanyCustomer> idSpec = (root, query, builder) -> {
return builder.equal(root.get("id"), id);
};
nameSpec = nameSpec.or(idSpec);
} catch (Exception ignored) {
}
}
List<CompanyCustomerEntity> searched = companyCustomerEntityService.search(searchText);
if (!searched.isEmpty()) {
nameSpec = SpecificationUtils.or(nameSpec, (root, query, builder) -> {
return builder.in(root.get("id")).value(searched.stream()
.map(CompanyCustomerEntity::getCustomer)
.filter(Objects::nonNull)
.map(CompanyCustomer::getId)
.collect(Collectors.toSet()));
});
}
return nameSpec;
}
@Override
public List<CompanyCustomer> search(String searchText) {
Specification<CompanyCustomer> spec = getSpecification(searchText);
return companyCustomerRepository.findAll(spec, Pageable.ofSize(10)).getContent();
}
@Override
public <T, F extends CompanyBasicFile<T>, ID> void deleteFile(F file) {
CompanyCustomerFile customerFile = (CompanyCustomerFile) file;
companyCustomerFileService.delete(customerFile);
}
public File getBasePath() {
return new File(confService.getString(KEY_BASE_PATH));
}
/**
* 重置 客户文件
*
* @param companyCustomer 客户对象
* @param status 输出
*/
public boolean reBuildingFiles(CompanyCustomer companyCustomer, Consumer<String> status) {
List<CompanyCustomerFile> dbFiles = companyCustomerFileService.findAllByCustomer(companyCustomer);
Map<String, CompanyCustomerFile> map = new HashMap<>();
boolean modified = fetchDbFiles(dbFiles, map, status);
// 客户目录下
List<CompanyCustomerFile> retrieveFiles = new ArrayList<>();
List<File> needMoveToCompanyPath = new ArrayList<>();
// TODO 客户有曾用名,可能存在多个目录
fetchFiles(companyCustomer.getPath(), needMoveToCompanyPath, retrieveFiles, map, status);
// 移动文件到公司目录下 to company path
moveFileToCompany(companyCustomer.getCompany(), needMoveToCompanyPath);
status.accept("导入 " + retrieveFiles.size() + " 个文件");
if (!retrieveFiles.isEmpty()) {
// update db
retrieveFiles.forEach(v -> v.setCustomer(companyCustomer));
companyCustomerFileService.saveAll(retrieveFiles);
modified = true;
}
return modified;
}
@Override
protected <T, F extends CompanyBasicFile<T>> boolean fillFileAsDefaultType(F dbFile, File file,
Consumer<String> status) {
dbFile.setType((T) CompanyCustomerFileType.General);
fillFile(dbFile, file, null, status);
companyCustomerFileService.save((CompanyCustomerFile) dbFile);
return true;
}
@Override
protected <T, F extends CompanyBasicFile<T>> boolean fillFileAsEvaluationFile(F customerFile, File file,
List<File> fileList, Consumer<String> status) {
boolean modified = super.fillFileAsEvaluationFile(customerFile, file, fileList, status);
if (fileList != null) {
File jsonFile = null;
// 文件名
String fileName = file.getName();
// 文件名,不含后缀
String name = StringUtils.stripFilenameExtension(fileName);
String jsonFileName = name + FileUtils.JSON;
for (File f : fileList) {
// 查找存档文件
if (f.getName().equals(jsonFileName)) {
jsonFile = f;
break;
}
}
if (jsonFile != null) {
if (fileList.remove(jsonFile)) {
try {
updateEvaluationFileByJsonFile(customerFile, jsonFile, status);
} catch (IOException e) {
if (logger.isErrorEnabled()) {
logger.error(e.getMessage(), e);
}
}
}
}
}
return modified;
}
private <T, F extends CompanyBasicFile<T>> void updateEvaluationFileByJsonFile(F customerFile, File jsonFile,
Consumer<String> status) throws IOException {
ObjectMapper objectMapper = new ObjectMapper();
JsonNode root = objectMapper.readTree(jsonFile);
if (!root.isObject()) {
return;
}
ObjectNode data = (ObjectNode) root;
data.remove("file");
data.remove("signDate");
data.remove("valid");
JsonNode type = data.remove("type");
CompanyCustomerEvaluationFormFile formFile = companyCustomerFileService
.findCustomerEvaluationFormFileByCustomerFile((CompanyCustomerFile) customerFile);
objectMapper.updateValue(formFile, data);
logger.info("load json data from {}", jsonFile.getName());
formFile.setCatalog(type.asText());
companyCustomerEvaluationFormFileRepository.save(formFile);
// companyCustomerEvaluationFormFileRepository.save(formFile);
if (jsonFile.delete()) {
logger.info("delete json file {}", jsonFile.getName());
}
}
@Override
protected <T, F extends CompanyBasicFile<T>> F fillFileType(File file, List<File> fileList,
Consumer<String> status) {
CompanyCustomerFile customerFile = new CompanyCustomerFile();
customerFile.setType(CompanyCustomerFileType.General);
if (fillFile(customerFile, file, fileList, status)) {
return (F) customerFile;
}
return null;
}
@Override
protected <T, F extends CompanyBasicFile<T>> boolean setFileTypeAsEvaluationForm(F file) {
T type = file.getType();
if (type != CompanyCustomerFileType.EvaluationForm) {
file.setType((T) CompanyCustomerFileType.EvaluationForm);
return true;
}
return false;
}
protected boolean isEvaluationFile(String fileName) {
return (fileName.contains(CompanyCustomerConstant.EVALUATION_FORM_NAME1)
|| fileName.contains(CompanyCustomerConstant.EVALUATION_FORM_NAME2))
&& (FileUtils.withExtensions(fileName, FileUtils.JPG, FileUtils.JPEG,
FileUtils.PDF));
}
public boolean makePathAbsent(CompanyCustomer companyCustomer) {
String path = companyCustomer.getPath();
if (StringUtils.hasText(path)) {
File file = new File(path);
if (file.exists()) {
return false;
}
}
File dir = makePath(companyCustomer);
if (dir == null) {
return false;
}
if (!dir.exists()) {
return false;
}
companyCustomer.setPath(dir.getAbsolutePath());
return true;
}
private File makePath(CompanyCustomer companyCustomer) {
File basePath = getBasePath();
Company company = companyCustomer.getCompany();
if (!Hibernate.isInitialized(company)) {
company = companyService.findById(company.getId());
}
String companyName = company.getName();
String fileName = CompanyUtils.formatCompanyVendorId(companyCustomer.getId()) + "-"
+ CompanyFileUtils.escapeFileName(companyName);
File dir = new File(basePath, fileName);
if (!dir.exists()) {
if (!dir.mkdir()) {
return null;
}
}
return dir;
}
public Page<CompanyCustomer> findAll(Specification<CompanyCustomer> spec, Pageable pageable) {
return companyCustomerRepository.findAll(spec, pageable);
}
/**
* 将一个公司的客户信息转移到另一个公司,并保存在数据库中
*
* @param from 要转移的客户信息所属的公司
* @param to 要转移到的公司
*/
public void resetTo(Company from, Company to) {
// 这里使用Optional对象来处理可能为空的情况
Optional<CompanyCustomer> fromCustomer = companyCustomerRepository.findByCompany(from);
if (fromCustomer.isEmpty()) {
// 无效数据
return;
}
Optional<CompanyCustomer> toCustomer = companyCustomerRepository.findByCompany(to);
if (toCustomer.isEmpty()) {
CompanyCustomer customer = fromCustomer.get();
customer.setCompany(to);
// 保存更新后的CompanyCustomer对象到数据库
companyCustomerRepository.save(customer);
return;
}
// 把 fromCustomer 信息合并到 toCustomer
resetTo(fromCustomer.get(), toCustomer.get());
}
/***
* 合并两个CompanyCustomer对象并将fromCustomer的信息合并到toCustomer中并保存到数据库中。
*
* @param from 源客户对象
* @param to 目标客户对象
*/
public void resetTo(CompanyCustomer from, CompanyCustomer to) {
// file
companyCustomerFileService.resetTo(from, to);
// entity
companyCustomerEntityService.resetTo(from, to);
// 删除源客户对象
companyCustomerRepository.delete(from);
}
/**
* 删除 company 的 客户
*/
public void deleteByCompany(Company company) {
int deleted = companyCustomerRepository.deleteAllByCompany(company);
if (deleted > 0) {
if (logger.isInfoEnabled()) {
logger.info("Delete {} records by company:#{}", deleted, company.getId());
}
}
}
@Cacheable(key = "'catalog-'+#p0")
public CustomerCatalog findCatalogById(Integer id) {
return customerCatalogRepository.findById(id).orElse(null);
}
public List<CustomerCatalog> findAllCatalogs() {
return customerCatalogRepository.findAll();
}
@Cacheable(key = "'catalog-code-'+#p0")
public CustomerCatalog findCatalogByCode(String code) {
return customerCatalogRepository.findByCode(code).orElse(null);
}
@Caching(evict = {
@CacheEvict(key = "'catalog-'+#p0.id"),
@CacheEvict(key = "'catalog-code-'+#p0.code")
})
public CustomerCatalog save(CustomerCatalog catalog) {
return customerCatalogRepository.save(catalog);
}
}

View File

@@ -0,0 +1,51 @@
package com.ecep.contract.ds.other.controller;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.ecep.contract.ds.other.service.EmployeeService;
import com.ecep.contract.model.Employee;
@RestController
@RequestMapping("/employee")
public class EmployyeController {
@Autowired
private EmployeeService employeeService;
@RequestMapping("/findById")
public Employee findById(Integer id) {
return employeeService.findById(id);
}
@RequestMapping("/list")
public Page<Employee> list(
Map<String, Object> params,
@RequestParam(defaultValue = "0") int pageNumber,
@RequestParam(defaultValue = "10") int pageSize) {
Specification<Employee> spec = (root, query, cb) -> cb.conjunction();
Sort sort = Sort.by(Sort.Order.desc("id"));
Pageable pageable = PageRequest.of(pageNumber, pageSize, sort);
return employeeService.findAll(spec, pageable);
}
@RequestMapping("/save")
public Employee save(Employee employee) {
return employeeService.save(employee);
}
@RequestMapping("/delete")
public void delete(Integer id) {
Employee employee = employeeService.findById(id);
employeeService.delete(employee);
}
}

View File

@@ -0,0 +1,64 @@
package com.ecep.contract.ds.other.controller;
import java.util.concurrent.atomic.AtomicInteger;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import com.ecep.contract.MessageHolder;
import com.ecep.contract.cloud.u8.ctx.InventoryCtx;
import com.ecep.contract.ds.other.service.InventoryService;
import com.ecep.contract.model.Inventory;
import com.ecep.contract.ui.Tasker;
public class InventorySyncTask extends Tasker<Object> {
private InventoryCtx inventoryCtx;
@Override
protected Object execute(MessageHolder holder) throws Exception {
inventoryCtx = new InventoryCtx();
inventoryCtx.initializeRepository(holder);
InventoryService service = inventoryCtx.getInventoryService();
Pageable pageRequest = PageRequest.ofSize(200);
AtomicInteger counter = new AtomicInteger(0);
Specification<Inventory> spec = null;
long total = service.count(spec);
while (true) {
if (isCancelled()) {
break;
}
Page<Inventory> page = service.findAll(spec, pageRequest);
if (page.isEmpty()) {
break;
}
for (Inventory inventory : page) {
if (isCancelled()) {
break;
}
String prefix = counter.get() + " / " + total + "> #" + inventory.getId() + "> ";
MessageHolder subHolder = holder.sub(prefix);
syncInventory(inventory, subHolder);
updateProgress(counter.incrementAndGet(), total);
}
if (!page.hasNext()) {
break;
}
pageRequest = page.nextPageable();
}
updateProgress(1, 1);
return super.call();
}
private void syncInventory(Inventory inventory, MessageHolder holder) {
if (inventoryCtx.syncInventoryDetailByCode(inventory, inventory.getCode(), holder)) {
inventoryCtx.getInventoryService().save(inventory);
}
}
}

View File

@@ -0,0 +1,15 @@
package com.ecep.contract.ds.other.repository;
import java.util.Optional;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Repository;
import com.ecep.contract.ds.MyRepository;
import com.ecep.contract.model.Bank;
@Lazy
@Repository
public interface BankRepository extends MyRepository<Bank, Integer> {
Optional<Bank> findFirstByName(String name);
}

View File

@@ -0,0 +1,46 @@
package com.ecep.contract.ds.other.repository;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.repository.NoRepositoryBean;
import com.ecep.contract.model.BaseEnumEntity;
@NoRepositoryBean
public interface BaseEnumEntityRepository<N extends Enum<?>, T extends BaseEnumEntity<N>, ID>
extends JpaRepository<T, ID> {
List<T> findAllByLang(String lang);
default Map<N, T> getCompleteMapByLocal(String lang) {
HashMap<N, T> map = new HashMap<>();
for (T t : findAllByLang(lang)) {
map.put(t.getType(), t);
}
ArrayList<T> needSaves = new ArrayList<>();
for (N type : getEnumConstants()) {
T v = map.get(type);
if (v == null) {
v = newEntity();
v.setType(type);
v.setLang(lang);
v.setValue(type.name());
needSaves.add(v);
}
}
if (!needSaves.isEmpty()) {
for (T v : saveAll(needSaves)) {
map.put(v.getType(), v);
}
}
return map;
}
T newEntity();
N[] getEnumConstants();
}

View File

@@ -0,0 +1,20 @@
package com.ecep.contract.ds.other.repository;
import java.util.Optional;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Repository;
import com.ecep.contract.ds.MyRepository;
import com.ecep.contract.model.Department;
/**
* 部门 Repository
*/
@Lazy
@Repository
public interface DepartmentRepository extends MyRepository<Department, Integer> {
Optional<Department> findByName(String name);
Optional<Department> findByCode(String code);
}

View File

@@ -0,0 +1,24 @@
package com.ecep.contract.ds.other.repository;
import java.util.List;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.stereotype.Repository;
import com.ecep.contract.model.Employee;
import com.ecep.contract.model.EmployeeAuthBind;
@Lazy
@Repository
public interface EmployeeAuthBindRepository extends
// JDBC interfaces
CrudRepository<EmployeeAuthBind, Integer>, PagingAndSortingRepository<EmployeeAuthBind, Integer>,
// JPA interfaces
JpaRepository<EmployeeAuthBind, Integer>, JpaSpecificationExecutor<EmployeeAuthBind> {
List<EmployeeAuthBind> findAllByEmployee(Employee employee, Sort sort);
}

View File

@@ -0,0 +1,20 @@
package com.ecep.contract.ds.other.repository;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.stereotype.Repository;
import com.ecep.contract.model.EmployeeLoginHistory;
@Lazy
@Repository
public interface EmployeeLoginHistoryRepository extends
// JDBC interfaces
CrudRepository<EmployeeLoginHistory, Integer>,
PagingAndSortingRepository<EmployeeLoginHistory, Integer>,
// JPA interfaces
JpaRepository<EmployeeLoginHistory, Integer>, JpaSpecificationExecutor<EmployeeLoginHistory> {
}

View File

@@ -0,0 +1,28 @@
package com.ecep.contract.ds.other.repository;
import java.util.Optional;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
import com.ecep.contract.ds.MyRepository;
import com.ecep.contract.model.Employee;
@Lazy
@Repository
public interface EmployeeRepository extends MyRepository<Employee, Integer> {
Optional<Employee> findByAccount(String username);
Optional<Employee> findByName(String name);
Optional<Employee> findByAlias(String alias);
Optional<Employee> findByCode(String personCode);
@Modifying
@Query(value = "update EMPLOYEE_LOGIN_HISTORY e set e.LATEST_ACTIVE = now() where e.id = ?1", nativeQuery = true)
void updateActive(int sessionId);
}

View File

@@ -0,0 +1,18 @@
package com.ecep.contract.ds.other.repository;
import java.util.Optional;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Repository;
import com.ecep.contract.ds.MyRepository;
import com.ecep.contract.model.EmployeeRole;
@Lazy
@Repository
public interface EmployeeRoleRepository extends MyRepository<EmployeeRole, Integer> {
Optional<EmployeeRole> findByName(String name);
Optional<EmployeeRole> findByCode(String personCode);
}

Some files were not shown because too many files have changed in this diff Show More