ouchuangxin 5 роки тому
батько
коміт
cf27edb2b3
61 змінених файлів з 1737 додано та 0 видалено
  1. 90 0
      leave-service/pom.xml
  2. 14 0
      leave-service/src/main/java/ddd/leave/Application.java
  3. 67 0
      leave-service/src/main/java/ddd/leave/application/service/LeaveApplicationService.java
  4. 22 0
      leave-service/src/main/java/ddd/leave/application/service/LoginApplicationService.java
  5. 35 0
      leave-service/src/main/java/ddd/leave/application/service/PersonApplicationService.java
  6. 16 0
      leave-service/src/main/java/ddd/leave/domain/leave/entity/ApprovalInfo.java
  7. 69 0
      leave-service/src/main/java/ddd/leave/domain/leave/entity/Leave.java
  8. 17 0
      leave-service/src/main/java/ddd/leave/domain/leave/entity/valueobject/Applicant.java
  9. 5 0
      leave-service/src/main/java/ddd/leave/domain/leave/entity/valueobject/ApprovalType.java
  10. 28 0
      leave-service/src/main/java/ddd/leave/domain/leave/entity/valueobject/Approver.java
  11. 5 0
      leave-service/src/main/java/ddd/leave/domain/leave/entity/valueobject/LeaveType.java
  12. 5 0
      leave-service/src/main/java/ddd/leave/domain/leave/entity/valueobject/Status.java
  13. 24 0
      leave-service/src/main/java/ddd/leave/domain/leave/event/LeaveEvent.java
  14. 8 0
      leave-service/src/main/java/ddd/leave/domain/leave/event/LeaveEventType.java
  15. 20 0
      leave-service/src/main/java/ddd/leave/domain/leave/repository/facade/LeaveRepositoryInterface.java
  16. 17 0
      leave-service/src/main/java/ddd/leave/domain/leave/repository/mapper/ApprovalInfoDao.java
  17. 15 0
      leave-service/src/main/java/ddd/leave/domain/leave/repository/mapper/LeaveDao.java
  18. 13 0
      leave-service/src/main/java/ddd/leave/domain/leave/repository/mapper/LeaveEventDao.java
  19. 66 0
      leave-service/src/main/java/ddd/leave/domain/leave/repository/persistence/LeaveRepositoryImpl.java
  20. 26 0
      leave-service/src/main/java/ddd/leave/domain/leave/repository/po/ApprovalInfoPO.java
  21. 23 0
      leave-service/src/main/java/ddd/leave/domain/leave/repository/po/LeaveEventPO.java
  22. 42 0
      leave-service/src/main/java/ddd/leave/domain/leave/repository/po/LeavePO.java
  23. 92 0
      leave-service/src/main/java/ddd/leave/domain/leave/service/LeaveDomainService.java
  24. 100 0
      leave-service/src/main/java/ddd/leave/domain/leave/service/LeaveFactory.java
  25. 39 0
      leave-service/src/main/java/ddd/leave/domain/person/entity/Person.java
  26. 12 0
      leave-service/src/main/java/ddd/leave/domain/person/entity/Relationship.java
  27. 7 0
      leave-service/src/main/java/ddd/leave/domain/person/entity/valueobject/PersonStatus.java
  28. 6 0
      leave-service/src/main/java/ddd/leave/domain/person/entity/valueobject/PersonType.java
  29. 15 0
      leave-service/src/main/java/ddd/leave/domain/person/repository/facade/PersonRepository.java
  30. 15 0
      leave-service/src/main/java/ddd/leave/domain/person/repository/mapper/PersonDao.java
  31. 37 0
      leave-service/src/main/java/ddd/leave/domain/person/repository/persistence/PersonRepositoryImpl.java
  32. 30 0
      leave-service/src/main/java/ddd/leave/domain/person/repository/po/PersonPO.java
  33. 16 0
      leave-service/src/main/java/ddd/leave/domain/person/repository/po/RelationshipPO.java
  34. 82 0
      leave-service/src/main/java/ddd/leave/domain/person/service/PersonDomainService.java
  35. 43 0
      leave-service/src/main/java/ddd/leave/domain/person/service/PersonFactory.java
  36. 21 0
      leave-service/src/main/java/ddd/leave/domain/rule/entity/ApprovalRule.java
  37. 8 0
      leave-service/src/main/java/ddd/leave/domain/rule/repository/facade/ApprovalRuleRepositoryInterface.java
  38. 12 0
      leave-service/src/main/java/ddd/leave/domain/rule/repository/mapper/ApprovalRuleDao.java
  39. 22 0
      leave-service/src/main/java/ddd/leave/domain/rule/repository/persistence/ApprovalRuleRepositoryImpl.java
  40. 24 0
      leave-service/src/main/java/ddd/leave/domain/rule/repository/po/ApprovalRulePO.java
  41. 21 0
      leave-service/src/main/java/ddd/leave/domain/rule/service/ApprovalRuleDomainService.java
  42. 13 0
      leave-service/src/main/java/ddd/leave/infrastructure/client/AuthFeignClient.java
  43. 33 0
      leave-service/src/main/java/ddd/leave/infrastructure/common/api/Response.java
  44. 14 0
      leave-service/src/main/java/ddd/leave/infrastructure/common/event/DomainEvent.java
  45. 13 0
      leave-service/src/main/java/ddd/leave/infrastructure/common/event/EventPublisher.java
  46. 31 0
      leave-service/src/main/java/ddd/leave/infrastructure/util/DateUtil.java
  47. 10 0
      leave-service/src/main/java/ddd/leave/infrastructure/util/IdGenerator.java
  48. 22 0
      leave-service/src/main/java/ddd/leave/interfaces/assembler/ApplicantAssembler.java
  49. 23 0
      leave-service/src/main/java/ddd/leave/interfaces/assembler/ApprovalInfoAssembler.java
  50. 22 0
      leave-service/src/main/java/ddd/leave/interfaces/assembler/ApproverAssembler.java
  51. 45 0
      leave-service/src/main/java/ddd/leave/interfaces/assembler/LeaveAssembler.java
  52. 34 0
      leave-service/src/main/java/ddd/leave/interfaces/assembler/PersonAssembler.java
  53. 13 0
      leave-service/src/main/java/ddd/leave/interfaces/dto/ApplicantDTO.java
  54. 12 0
      leave-service/src/main/java/ddd/leave/interfaces/dto/ApprovalInfoDTO.java
  55. 9 0
      leave-service/src/main/java/ddd/leave/interfaces/dto/ApproverDTO.java
  56. 21 0
      leave-service/src/main/java/ddd/leave/interfaces/dto/LeaveDTO.java
  57. 15 0
      leave-service/src/main/java/ddd/leave/interfaces/dto/PersonDTO.java
  58. 28 0
      leave-service/src/main/java/ddd/leave/interfaces/facade/AuthApi.java
  59. 74 0
      leave-service/src/main/java/ddd/leave/interfaces/facade/LeaveApi.java
  60. 62 0
      leave-service/src/main/java/ddd/leave/interfaces/facade/PersonApi.java
  61. 14 0
      leave-service/src/main/resources/application.yml

+ 90 - 0
leave-service/pom.xml

@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>ddd</groupId>
+    <artifactId>leave-service</artifactId>
+    <version>1.0-SNAPSHOT</version>
+
+    <parent>
+        <groupId>org.springframework.boot</groupId>
+        <artifactId>spring-boot-starter-parent</artifactId>
+        <version>2.1.8.RELEASE</version>
+        <relativePath/>
+    </parent>
+
+    <dependencyManagement>
+        <dependencies>
+            <dependency>
+                <groupId>org.springframework.cloud</groupId>
+                <artifactId>spring-cloud-dependencies</artifactId>
+                <version>Greenwich.RELEASE</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+        </dependencies>
+    </dependencyManagement>
+
+    <dependencies>
+
+        <dependency>
+            <groupId>org.springframework.cloud</groupId>
+            <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.cloud</groupId>
+            <artifactId>spring-cloud-starter-feign</artifactId>
+            <version>1.4.0.RELEASE</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-data-jpa</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>com.github.meixuesong</groupId>
+            <artifactId>aggregate-persistence</artifactId>
+            <version>1.0.0</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.postgresql</groupId>
+            <artifactId>postgresql</artifactId>
+            <version>42.2.2</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>fastjson</artifactId>
+            <version>1.2.4</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.jetbrains</groupId>
+            <artifactId>annotations</artifactId>
+            <version>RELEASE</version>
+            <scope>compile</scope>
+        </dependency>
+
+    </dependencies>
+</project>

+ 14 - 0
leave-service/src/main/java/ddd/leave/Application.java

@@ -0,0 +1,14 @@
+package ddd.leave;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cloud.openfeign.EnableFeignClients;
+
+@EnableFeignClients
+@SpringBootApplication
+public class Application {
+
+    public static void main(String[] args) {
+        SpringApplication.run(Application.class, args);
+    }
+}

+ 67 - 0
leave-service/src/main/java/ddd/leave/application/service/LeaveApplicationService.java

@@ -0,0 +1,67 @@
+package ddd.leave.application.service;
+
+import ddd.leave.domain.leave.entity.valueobject.Approver;
+import ddd.leave.domain.leave.entity.Leave;
+import ddd.leave.domain.leave.service.LeaveDomainService;
+import ddd.leave.domain.person.entity.Person;
+import ddd.leave.domain.person.repository.po.PersonPO;
+import ddd.leave.domain.person.service.PersonDomainService;
+import ddd.leave.domain.rule.entity.ApprovalRule;
+import ddd.leave.domain.rule.service.ApprovalRuleDomainService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+@Service
+public class LeaveApplicationService{
+
+    @Autowired
+    LeaveDomainService leaveDomainService;
+    @Autowired
+    PersonDomainService personDomainService;
+    @Autowired
+    ApprovalRuleDomainService approvalRuleDomainService;
+
+    /**
+     * 创建一个请假申请并为审批人生成任务
+     * @param leave
+     */
+    public void createLeaveInfo(Leave leave){
+        //get approval leader max level by rule
+        int leaderMaxLevel = approvalRuleDomainService.getLeaderMaxLevel(leave.getApplicant().getPersonType(), leave.getType().toString(), leave.getDuration());
+        //find next approver
+        Person approver = personDomainService.findFirstApprover(leave.getApplicant().getPersonId(), leaderMaxLevel);
+        leaveDomainService.createLeave(leave, leaderMaxLevel, Approver.fromPerson(approver));
+    }
+
+    /**
+     * 更新请假单基本信息
+     * @param leave
+     */
+    public void updateLeaveInfo(Leave leave){
+        leaveDomainService.updateLeaveInfo(leave);
+    }
+
+    /**
+     * 提交审批,更新请假单信息
+     * @param leave
+     */
+    public void submitApproval(Leave leave){
+        //find next approver
+        Person approver = personDomainService.findNextApprover(leave.getApprover().getPersonId(), leave.getLeaderMaxLevel());
+        leaveDomainService.submitApproval(leave, Approver.fromPerson(approver));
+    }
+
+    public Leave getLeaveInfo(String leaveId){
+        return leaveDomainService.getLeaveInfo(leaveId);
+    }
+
+    public List<Leave> queryLeaveInfosByApplicant(String applicantId){
+        return leaveDomainService.queryLeaveInfosByApplicant(applicantId);
+    }
+
+    public List<Leave> queryLeaveInfosByApprover(String approverId){
+        return leaveDomainService.queryLeaveInfosByApprover(approverId);
+    }
+}

+ 22 - 0
leave-service/src/main/java/ddd/leave/application/service/LoginApplicationService.java

@@ -0,0 +1,22 @@
+package ddd.leave.application.service;
+
+import ddd.leave.domain.person.entity.Person;
+import ddd.leave.domain.person.service.PersonDomainService;
+import ddd.leave.infrastructure.client.AuthFeignClient;
+import ddd.leave.infrastructure.common.api.Response;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+@Service
+public class LoginApplicationService{
+
+    @Autowired
+    AuthFeignClient authService;
+    @Autowired
+    PersonDomainService personDomainService;
+
+    public Response login(Person person){
+        //调用鉴权微服务
+        return authService.login(person);
+    }
+}

+ 35 - 0
leave-service/src/main/java/ddd/leave/application/service/PersonApplicationService.java

@@ -0,0 +1,35 @@
+package ddd.leave.application.service;
+
+import ddd.leave.domain.person.entity.Person;
+import ddd.leave.domain.person.service.PersonDomainService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+@Service
+public class PersonApplicationService {
+
+    @Autowired
+    PersonDomainService personDomainService;
+
+    public void create(Person person) {
+        personDomainService.create(person);
+    }
+
+    public void update(Person person) {
+        personDomainService.update(person);
+    }
+
+    public void deleteById(String personId) {
+        personDomainService.deleteById(personId);
+    }
+
+    public Person findById(String personId) {
+        return null;
+    }
+
+    public Person findFirstApprover(String applicantId, int leaderMaxLevel) {
+        return personDomainService.findFirstApprover(applicantId, leaderMaxLevel);
+    }
+
+
+}

+ 16 - 0
leave-service/src/main/java/ddd/leave/domain/leave/entity/ApprovalInfo.java

@@ -0,0 +1,16 @@
+package ddd.leave.domain.leave.entity;
+
+import ddd.leave.domain.leave.entity.valueobject.ApprovalType;
+import ddd.leave.domain.leave.entity.valueobject.Approver;
+import lombok.Data;
+
+@Data
+public class ApprovalInfo {
+
+    String approvalInfoId;
+    Approver approver;
+    ApprovalType approvalType;
+    String msg;
+    long time;
+
+}

+ 69 - 0
leave-service/src/main/java/ddd/leave/domain/leave/entity/Leave.java

@@ -0,0 +1,69 @@
+package ddd.leave.domain.leave.entity;
+
+import ddd.leave.domain.leave.entity.valueobject.Applicant;
+import ddd.leave.domain.leave.entity.valueobject.Approver;
+import ddd.leave.domain.leave.entity.valueobject.LeaveType;
+import ddd.leave.domain.leave.entity.valueobject.Status;
+import lombok.Data;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 请假单信息
+ */
+@Data
+public class Leave {
+
+    String id;
+    Applicant applicant;
+    Approver approver;
+    LeaveType type;
+    Status status;
+    Date startTime;
+    Date endTime;
+    long duration;
+    //审批领导的最大级别
+    int leaderMaxLevel;
+    ApprovalInfo currentApprovalInfo;
+    List<ApprovalInfo> historyApprovalInfos;
+
+    public long getDuration() {
+        return endTime.getTime() - startTime.getTime();
+    }
+
+    public Leave addHistoryApprovalInfo(ApprovalInfo approvalInfo) {
+        if (historyApprovalInfos == null)
+            historyApprovalInfos = new ArrayList<>();
+        this.historyApprovalInfos.add(approvalInfo);
+        return this;
+    }
+
+    public Leave create(){
+        this.setStatus(Status.APPROVING);
+        this.setStartTime(new Date());
+        return this;
+    }
+
+    public Leave agree(Approver nextApprover){
+        this.setStatus(Status.APPROVING);
+        this.setApprover(nextApprover);
+        return this;
+    }
+
+    public Leave reject(Approver approver){
+        this.setApprover(approver);
+        this.setStatus(Status.REJECTED);
+        this.setApprover(null);
+        return this;
+    }
+
+    public Leave finish(){
+        this.setApprover(null);
+        this.setStatus(Status.APPROVED);
+        this.setEndTime(new Date());
+        this.setDuration(this.getEndTime().getTime() - this.getStartTime().getTime());
+        return this;
+    }
+}

+ 17 - 0
leave-service/src/main/java/ddd/leave/domain/leave/entity/valueobject/Applicant.java

@@ -0,0 +1,17 @@
+package ddd.leave.domain.leave.entity.valueobject;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class Applicant {
+
+    String personId;
+    String personName;
+    String personType;
+}

+ 5 - 0
leave-service/src/main/java/ddd/leave/domain/leave/entity/valueobject/ApprovalType.java

@@ -0,0 +1,5 @@
+package ddd.leave.domain.leave.entity.valueobject;
+
+public enum  ApprovalType {
+    AGREE, REJECT
+}

+ 28 - 0
leave-service/src/main/java/ddd/leave/domain/leave/entity/valueobject/Approver.java

@@ -0,0 +1,28 @@
+package ddd.leave.domain.leave.entity.valueobject;
+
+import ddd.leave.domain.person.entity.Person;
+import ddd.leave.domain.person.repository.po.PersonPO;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@Builder
+public class Approver {
+
+    String personId;
+    String personName;
+    int level;
+
+    public static Approver fromPerson(Person person){
+        Approver approver = new Approver();
+        approver.setPersonId(person.getPersonId());
+        approver.setPersonName(person.getPersonName());
+        approver.setLevel(person.getRoleLevel());
+        return approver;
+    }
+
+}

+ 5 - 0
leave-service/src/main/java/ddd/leave/domain/leave/entity/valueobject/LeaveType.java

@@ -0,0 +1,5 @@
+package ddd.leave.domain.leave.entity.valueobject;
+
+public enum LeaveType {
+    Internal, External, Official
+}

+ 5 - 0
leave-service/src/main/java/ddd/leave/domain/leave/entity/valueobject/Status.java

@@ -0,0 +1,5 @@
+package ddd.leave.domain.leave.entity.valueobject;
+
+public enum Status {
+    APPROVING, APPROVED, REJECTED
+}

+ 24 - 0
leave-service/src/main/java/ddd/leave/domain/leave/event/LeaveEvent.java

@@ -0,0 +1,24 @@
+package ddd.leave.domain.leave.event;
+
+import com.alibaba.fastjson.JSON;
+import ddd.leave.domain.leave.entity.Leave;
+import ddd.leave.infrastructure.common.event.DomainEvent;
+import ddd.leave.infrastructure.util.IdGenerator;
+import lombok.Data;
+
+import java.util.Date;
+
+@Data
+public class LeaveEvent extends DomainEvent {
+
+    LeaveEventType leaveEventType;
+
+    public static LeaveEvent create(LeaveEventType eventType, Leave leave){
+        LeaveEvent event = new LeaveEvent();
+        event.setId(IdGenerator.nextId());
+        event.setLeaveEventType(eventType);
+        event.setTimestamp(new Date());
+        event.setData(JSON.toJSONString(leave));
+        return event;
+    }
+}

+ 8 - 0
leave-service/src/main/java/ddd/leave/domain/leave/event/LeaveEventType.java

@@ -0,0 +1,8 @@
+package ddd.leave.domain.leave.event;
+
+public enum  LeaveEventType {
+    CREATE_EVENT,
+    AGREE_EVENT,
+    REJECT_EVENT,
+    APPROVED_EVENT
+}

+ 20 - 0
leave-service/src/main/java/ddd/leave/domain/leave/repository/facade/LeaveRepositoryInterface.java

@@ -0,0 +1,20 @@
+package ddd.leave.domain.leave.repository.facade;
+
+import ddd.leave.domain.leave.repository.po.LeaveEventPO;
+import ddd.leave.domain.leave.repository.po.LeavePO;
+
+import java.util.List;
+
+public interface LeaveRepositoryInterface {
+
+    void save(LeavePO leavePO);
+
+    void saveEvent(LeaveEventPO leaveEventPO);
+
+    LeavePO findById(String id);
+
+    List<LeavePO> queryByApplicantId(String applicantId);
+
+    List<LeavePO> queryByApproverId(String approverId);
+
+}

+ 17 - 0
leave-service/src/main/java/ddd/leave/domain/leave/repository/mapper/ApprovalInfoDao.java

@@ -0,0 +1,17 @@
+package ddd.leave.domain.leave.repository.mapper;
+
+import ddd.leave.domain.leave.repository.po.ApprovalInfoPO;
+import ddd.leave.domain.leave.repository.po.LeavePO;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+@Repository
+public interface ApprovalInfoDao extends JpaRepository<ApprovalInfoPO, String> {
+
+    List<LeavePO> queryByApplicantId(String applicantId);
+
+    List<ApprovalInfoPO> queryByLeaveId(String leaveId);
+
+}

+ 15 - 0
leave-service/src/main/java/ddd/leave/domain/leave/repository/mapper/LeaveDao.java

@@ -0,0 +1,15 @@
+package ddd.leave.domain.leave.repository.mapper;
+
+import ddd.leave.domain.leave.repository.po.LeavePO;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+@Repository
+public interface LeaveDao extends JpaRepository<LeavePO, String> {
+
+    List<LeavePO> queryByApplicantId(String applicantId);
+
+    List<LeavePO> queryByApproverId(String approverId);
+}

+ 13 - 0
leave-service/src/main/java/ddd/leave/domain/leave/repository/mapper/LeaveEventDao.java

@@ -0,0 +1,13 @@
+package ddd.leave.domain.leave.repository.mapper;
+
+import ddd.leave.domain.leave.repository.po.LeaveEventPO;
+import ddd.leave.domain.leave.repository.po.LeavePO;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+@Repository
+public interface LeaveEventDao extends JpaRepository<LeaveEventPO, String> {
+
+}

+ 66 - 0
leave-service/src/main/java/ddd/leave/domain/leave/repository/persistence/LeaveRepositoryImpl.java

@@ -0,0 +1,66 @@
+package ddd.leave.domain.leave.repository.persistence;
+
+import ddd.leave.domain.leave.repository.facade.LeaveRepositoryInterface;
+import ddd.leave.domain.leave.repository.mapper.ApprovalInfoDao;
+import ddd.leave.domain.leave.repository.mapper.LeaveDao;
+import ddd.leave.domain.leave.repository.mapper.LeaveEventDao;
+import ddd.leave.domain.leave.repository.po.ApprovalInfoPO;
+import ddd.leave.domain.leave.repository.po.LeaveEventPO;
+import ddd.leave.domain.leave.repository.po.LeavePO;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+/**
+ * persist entity and handle event in repository
+ */
+@Repository
+public class LeaveRepositoryImpl implements LeaveRepositoryInterface {
+
+    @Autowired
+    LeaveDao leaveDao;
+    @Autowired
+    ApprovalInfoDao approvalInfoDao;
+    @Autowired
+    LeaveEventDao leaveEventDao;
+
+    public void save(LeavePO leavePO) {
+        //persist leave entity
+        leaveDao.save(leavePO);
+        approvalInfoDao.saveAll(leavePO.getHistoryApprovalInfoPOList());
+    }
+
+    public void saveEvent(LeaveEventPO leaveEventPO){
+        leaveEventDao.save(leaveEventPO);
+    }
+
+    @Override
+    public LeavePO findById(String id) {
+        return leaveDao.findById(id)
+                .orElseThrow(() -> new RuntimeException("leave not found"));
+    }
+
+    @Override
+    public List<LeavePO> queryByApplicantId(String applicantId) {
+        List<LeavePO> leavePOList = leaveDao.queryByApplicantId(applicantId);
+        leavePOList.stream()
+                .forEach(leavePO -> {
+                    List<ApprovalInfoPO> approvalInfoPOList = approvalInfoDao.queryByLeaveId(leavePO.getId());
+                    leavePO.setHistoryApprovalInfoPOList(approvalInfoPOList);
+                });
+        return leavePOList;
+    }
+
+    @Override
+    public List<LeavePO> queryByApproverId(String approverId) {
+        List<LeavePO> leavePOList = leaveDao.queryByApproverId(approverId);
+        leavePOList.stream()
+                .forEach(leavePO -> {
+                    List<ApprovalInfoPO> approvalInfoPOList = approvalInfoDao.queryByLeaveId(leavePO.getId());
+                    leavePO.setHistoryApprovalInfoPOList(approvalInfoPOList);
+                });
+        return leavePOList;
+    }
+
+}

+ 26 - 0
leave-service/src/main/java/ddd/leave/domain/leave/repository/po/ApprovalInfoPO.java

@@ -0,0 +1,26 @@
+package ddd.leave.domain.leave.repository.po;
+
+import lombok.Data;
+import org.hibernate.annotations.GenericGenerator;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+
+@Entity
+@Data
+public class ApprovalInfoPO {
+
+    @Id
+    @GenericGenerator(name = "idGenerator", strategy = "uuid")
+    @GeneratedValue(generator = "idGenerator")
+    String approvalInfoId;
+    String leaveId;
+    String applicantId;
+    String approverId;
+    int approverLevel;
+    String approverName;
+    String msg;
+    long time;
+
+}

+ 23 - 0
leave-service/src/main/java/ddd/leave/domain/leave/repository/po/LeaveEventPO.java

@@ -0,0 +1,23 @@
+package ddd.leave.domain.leave.repository.po;
+
+import ddd.leave.domain.leave.event.LeaveEventType;
+import lombok.Data;
+import org.hibernate.annotations.GenericGenerator;
+
+import javax.persistence.*;
+import java.util.Date;
+
+@Data
+@Entity
+public class LeaveEventPO {
+
+    @Id
+    @GenericGenerator(name = "idGenerator", strategy = "uuid") //这个是hibernate的注解/生成32位UUID
+    @GeneratedValue(generator = "idGenerator")
+    int id;
+    @Enumerated(EnumType.STRING)
+    LeaveEventType leaveEventType;
+    Date timestamp;
+    String source;
+    String data;
+}

+ 42 - 0
leave-service/src/main/java/ddd/leave/domain/leave/repository/po/LeavePO.java

@@ -0,0 +1,42 @@
+package ddd.leave.domain.leave.repository.po;
+
+import ddd.leave.domain.leave.entity.Leave;
+import ddd.leave.domain.leave.entity.valueobject.LeaveType;
+import ddd.leave.domain.leave.entity.valueobject.Status;
+import ddd.leave.domain.person.entity.valueobject.PersonType;
+import lombok.Data;
+import org.hibernate.annotations.GenericGenerator;
+
+import javax.persistence.*;
+import java.util.*;
+
+@Entity
+@Table(name = "Leave")
+@Data
+public class LeavePO {
+
+    @Id
+    @GenericGenerator(name="idGenerator", strategy="uuid") //这个是hibernate的注解/生成32位UUID
+    @GeneratedValue(generator="idGenerator")
+    String id;
+    String applicantId;
+    String applicantName;
+    @Enumerated(EnumType.STRING)
+    PersonType applicantType;
+    String approverId;
+    String approverName;
+    @Enumerated(EnumType.STRING)
+    LeaveType leaveType;
+    @Enumerated(EnumType.STRING)
+    Status status;
+    Date startTime;
+    Date endTime;
+    long duration;
+    @Transient
+    List<ApprovalInfoPO> historyApprovalInfoPOList;
+
+    public Leave toLeave() {
+        return new Leave();
+    }
+
+}

+ 92 - 0
leave-service/src/main/java/ddd/leave/domain/leave/service/LeaveDomainService.java

@@ -0,0 +1,92 @@
+package ddd.leave.domain.leave.service;
+
+import ddd.leave.domain.leave.entity.Leave;
+import ddd.leave.domain.leave.entity.valueobject.ApprovalType;
+import ddd.leave.domain.leave.entity.valueobject.Approver;
+import ddd.leave.domain.leave.event.LeaveEvent;
+import ddd.leave.domain.leave.event.LeaveEventType;
+import ddd.leave.domain.leave.repository.facade.LeaveRepositoryInterface;
+import ddd.leave.domain.leave.repository.po.LeavePO;
+import ddd.leave.infrastructure.common.event.EventPublisher;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+@Service
+@Slf4j
+public class LeaveDomainService {
+
+    @Autowired
+    EventPublisher eventPublisher;
+    @Autowired
+    LeaveRepositoryInterface leaveRepositoryInterface;
+    @Autowired
+    LeaveFactory leaveFactory;
+
+    @Transactional
+    public void createLeave(Leave leave, int leaderMaxLevel, Approver approver) {
+        leave.setLeaderMaxLevel(leaderMaxLevel);
+        leave.setApprover(approver);
+        leave.create();
+        leaveRepositoryInterface.save(leaveFactory.createLeavePO(leave));
+        LeaveEvent event = LeaveEvent.create(LeaveEventType.CREATE_EVENT, leave);
+        leaveRepositoryInterface.saveEvent(leaveFactory.createLeaveEventPO(event));
+        eventPublisher.publish(event);
+    }
+
+    @Transactional
+    public void updateLeaveInfo(Leave leave) {
+        LeavePO po = leaveRepositoryInterface.findById(leave.getId());
+        if (null == po) {
+            throw new RuntimeException("leave does not exist");
+        }
+        leaveRepositoryInterface.save(leaveFactory.createLeavePO(leave));
+    }
+
+    @Transactional
+    public void submitApproval(Leave leave, Approver approver) {
+        LeaveEvent event;
+        if ( ApprovalType.REJECT == leave.getCurrentApprovalInfo().getApprovalType()) {
+            //reject, then the leave is finished with REJECTED status
+            leave.reject(approver);
+            event = LeaveEvent.create(LeaveEventType.REJECT_EVENT, leave);
+        } else {
+            if (approver != null) {
+                //agree and has next approver
+                leave.agree(approver);
+                event = LeaveEvent.create(LeaveEventType.AGREE_EVENT, leave);
+            } else {
+                //agree and hasn't next approver, then the leave is finished with APPROVED status
+                leave.finish();
+                event = LeaveEvent.create(LeaveEventType.APPROVED_EVENT, leave);
+            }
+        }
+        leave.addHistoryApprovalInfo(leave.getCurrentApprovalInfo());
+        leaveRepositoryInterface.save(leaveFactory.createLeavePO(leave));
+        leaveRepositoryInterface.saveEvent(leaveFactory.createLeaveEventPO(event));
+        eventPublisher.publish(event);
+    }
+
+    public Leave getLeaveInfo(String leaveId) {
+        LeavePO leavePO = leaveRepositoryInterface.findById(leaveId);
+        return leaveFactory.getLeave(leavePO);
+    }
+
+    public List<Leave> queryLeaveInfosByApplicant(String applicantId) {
+        List<LeavePO> leavePOList = leaveRepositoryInterface.queryByApplicantId(applicantId);
+        return leavePOList.stream()
+                .map(leavePO -> leaveFactory.getLeave(leavePO))
+                .collect(Collectors.toList());
+    }
+
+    public List<Leave> queryLeaveInfosByApprover(String approverId) {
+        List<LeavePO> leavePOList = leaveRepositoryInterface.queryByApproverId(approverId);
+        return leavePOList.stream()
+                .map(leavePO -> leaveFactory.getLeave(leavePO))
+                .collect(Collectors.toList());
+    }
+}

+ 100 - 0
leave-service/src/main/java/ddd/leave/domain/leave/service/LeaveFactory.java

@@ -0,0 +1,100 @@
+package ddd.leave.domain.leave.service;
+
+import com.alibaba.fastjson.JSON;
+import ddd.leave.domain.leave.entity.ApprovalInfo;
+import ddd.leave.domain.leave.entity.Leave;
+import ddd.leave.domain.leave.entity.valueobject.Applicant;
+import ddd.leave.domain.leave.entity.valueobject.Approver;
+import ddd.leave.domain.leave.event.LeaveEvent;
+import ddd.leave.domain.leave.repository.po.ApprovalInfoPO;
+import ddd.leave.domain.leave.repository.po.LeaveEventPO;
+import ddd.leave.domain.leave.repository.po.LeavePO;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.UUID;
+import java.util.stream.Collectors;
+
+@Service
+public class LeaveFactory {
+
+    public LeavePO createLeavePO(Leave leave) {
+        LeavePO leavePO = new LeavePO();
+        leavePO.setId(UUID.randomUUID().toString());
+        leavePO.setApplicantId(leave.getApplicant().getPersonId());
+        leavePO.setApplicantName(leave.getApplicant().getPersonName());
+        leavePO.setApproverId(leave.getApprover().getPersonId());
+        leavePO.setApproverName(leave.getApprover().getPersonName());
+        leavePO.setStartTime(leave.getStartTime());
+        leavePO.setStatus(leave.getStatus());
+        List<ApprovalInfoPO> historyApprovalInfoPOList = approvalInfoPOListFromDO(leave);
+        leavePO.setHistoryApprovalInfoPOList(historyApprovalInfoPOList);
+        return leavePO;
+    }
+
+    public Leave getLeave(LeavePO leavePO) {
+        Leave leave = new Leave();
+        Applicant applicant = Applicant.builder()
+                .personId(leavePO.getApplicantId())
+                .personName(leavePO.getApplicantName())
+                .build();
+        leave.setApplicant(applicant);
+        Approver approver = Approver.builder()
+                .personId(leavePO.getApproverId())
+                .personName(leavePO.getApproverName())
+                .build();
+        leave.setApprover(approver);
+        leave.setStartTime(leave.getStartTime());
+        leave.setStatus(leave.getStatus());
+        List<ApprovalInfo> approvalInfos = getApprovalInfos(leavePO.getHistoryApprovalInfoPOList());
+        leave.setHistoryApprovalInfos(approvalInfos);
+        return leave;
+    }
+
+    public LeaveEventPO createLeaveEventPO(LeaveEvent leaveEvent){
+        LeaveEventPO eventPO = new LeaveEventPO();
+        eventPO.setLeaveEventType(leaveEvent.getLeaveEventType());
+        eventPO.setSource(leaveEvent.getSource());
+        eventPO.setTimestamp(leaveEvent.getTimestamp());
+        eventPO.setData(JSON.toJSONString(leaveEvent.getData()));
+        return eventPO;
+    }
+
+    private List<ApprovalInfoPO> approvalInfoPOListFromDO(Leave leave) {
+        return leave.getHistoryApprovalInfos()
+                .stream()
+                .map(approvalInfo -> approvalInfoPOFromDO(approvalInfo))
+                .collect(Collectors.toList());
+    }
+
+    private ApprovalInfoPO approvalInfoPOFromDO(ApprovalInfo approvalInfo){
+        ApprovalInfoPO po = new ApprovalInfoPO();
+        po.setApproverId(approvalInfo.getApprover().getPersonId());
+        po.setApproverLevel(approvalInfo.getApprover().getLevel());
+        po.setApproverName(approvalInfo.getApprover().getPersonName());
+        po.setApprovalInfoId(approvalInfo.getApprovalInfoId());
+        po.setMsg(approvalInfo.getMsg());
+        po.setTime(approvalInfo.getTime());
+        return po;
+    }
+
+    private ApprovalInfo approvalInfoFromPO(ApprovalInfoPO approvalInfoPO){
+        ApprovalInfo approvalInfo = new ApprovalInfo();
+        approvalInfo.setApprovalInfoId(approvalInfoPO.getApprovalInfoId());
+        Approver approver = Approver.builder()
+                .personId(approvalInfoPO.getApproverId())
+                .personName(approvalInfoPO.getApproverName())
+                .level(approvalInfoPO.getApproverLevel())
+                .build();
+        approvalInfo.setApprover(approver);
+        approvalInfo.setMsg(approvalInfoPO.getMsg());
+        approvalInfo.setTime(approvalInfoPO.getTime());
+        return approvalInfo;
+    }
+
+    private List<ApprovalInfo> getApprovalInfos(List<ApprovalInfoPO> approvalInfoPOList){
+        return approvalInfoPOList.stream()
+                .map(approvalInfoPO -> approvalInfoFromPO(approvalInfoPO))
+                .collect(Collectors.toList());
+    }
+}

+ 39 - 0
leave-service/src/main/java/ddd/leave/domain/person/entity/Person.java

@@ -0,0 +1,39 @@
+package ddd.leave.domain.person.entity;
+
+import ddd.leave.domain.person.entity.valueobject.PersonStatus;
+import ddd.leave.domain.person.entity.valueobject.PersonType;
+import lombok.Data;
+
+import java.util.Date;
+import java.util.List;
+
+@Data
+public class Person {
+
+    String personId;
+    String personName;
+    PersonType personType;
+    List<Relationship> relationships;
+    int roleLevel;
+    Date createTime;
+    Date lastModifyTime;
+    PersonStatus status;
+
+    public Person create(){
+        this.createTime = new Date();
+        this.status = PersonStatus.ENABLE;
+        return this;
+    }
+
+    public Person enable(){
+        this.lastModifyTime = new Date();
+        this.status = PersonStatus.ENABLE;
+        return this;
+    }
+
+    public Person disable(){
+        this.lastModifyTime = new Date();
+        this.status = PersonStatus.DISABLE;
+        return this;
+    }
+}

+ 12 - 0
leave-service/src/main/java/ddd/leave/domain/person/entity/Relationship.java

@@ -0,0 +1,12 @@
+package ddd.leave.domain.person.entity;
+
+import lombok.Data;
+
+@Data
+public class Relationship {
+
+    String id;
+    String personId;
+    String leaderId;
+    int leaderLevel;
+}

+ 7 - 0
leave-service/src/main/java/ddd/leave/domain/person/entity/valueobject/PersonStatus.java

@@ -0,0 +1,7 @@
+package ddd.leave.domain.person.entity.valueobject;
+
+public enum PersonStatus {
+
+    ENABLE,DISABLE
+
+}

+ 6 - 0
leave-service/src/main/java/ddd/leave/domain/person/entity/valueobject/PersonType.java

@@ -0,0 +1,6 @@
+package ddd.leave.domain.person.entity.valueobject;
+
+public enum PersonType {
+
+    INTERNAL, EXTERNAL
+}

+ 15 - 0
leave-service/src/main/java/ddd/leave/domain/person/repository/facade/PersonRepository.java

@@ -0,0 +1,15 @@
+package ddd.leave.domain.person.repository.facade;
+
+import ddd.leave.domain.person.repository.po.PersonPO;
+
+public interface PersonRepository {
+
+    void insert(PersonPO personPO);
+
+    void update(PersonPO personPO);
+
+    PersonPO findById(String id);
+
+    PersonPO findLeaderByPersonId(String personId);
+
+}

+ 15 - 0
leave-service/src/main/java/ddd/leave/domain/person/repository/mapper/PersonDao.java

@@ -0,0 +1,15 @@
+package ddd.leave.domain.person.repository.mapper;
+
+import ddd.leave.domain.person.repository.po.PersonPO;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+@Repository
+public interface PersonDao extends JpaRepository<PersonPO, String> {
+
+    @Query(value = "select p from PersonPO  p where p.relationshipPO.personId=?1")
+    PersonPO findLeaderByPersonId(String personId);
+}

+ 37 - 0
leave-service/src/main/java/ddd/leave/domain/person/repository/persistence/PersonRepositoryImpl.java

@@ -0,0 +1,37 @@
+package ddd.leave.domain.person.repository.persistence;
+
+import ddd.leave.domain.person.repository.po.PersonPO;
+import ddd.leave.domain.person.repository.facade.PersonRepository;
+import ddd.leave.domain.person.repository.mapper.PersonDao;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+@Repository
+public class PersonRepositoryImpl implements PersonRepository {
+
+    @Autowired
+    PersonDao personDao;
+
+    @Override
+    public void insert(PersonPO personPO) {
+        personDao.save(personPO);
+    }
+
+    @Override
+    public void update(PersonPO personPO) {
+        personDao.save(personPO);
+    }
+
+    @Override
+    public PersonPO findById(String id) {
+        return personDao.findById(id).orElseThrow(() -> new RuntimeException("未找到用户"));
+    }
+
+    @Override
+    public PersonPO findLeaderByPersonId(String personId) {
+        return personDao.findLeaderByPersonId(personId);
+    }
+
+}

+ 30 - 0
leave-service/src/main/java/ddd/leave/domain/person/repository/po/PersonPO.java

@@ -0,0 +1,30 @@
+package ddd.leave.domain.person.repository.po;
+
+import ddd.leave.domain.person.entity.valueobject.PersonStatus;
+import ddd.leave.domain.person.entity.valueobject.PersonType;
+import lombok.Data;
+
+import javax.persistence.*;
+import java.util.Date;
+
+@Data
+@Entity
+@Table(name = "person")
+public class PersonPO {
+
+    @Id
+    String personId;
+    String personName;
+    String departmentId;
+    @Enumerated(EnumType.STRING)
+    PersonType personType;
+    @Transient
+    String leaderId;
+    int roleLevel;
+    Date createTime;
+    Date lastModifyTime;
+    @Enumerated(EnumType.STRING)
+    PersonStatus status;
+    @OneToOne
+    RelationshipPO relationshipPO;
+}

+ 16 - 0
leave-service/src/main/java/ddd/leave/domain/person/repository/po/RelationshipPO.java

@@ -0,0 +1,16 @@
+package ddd.leave.domain.person.repository.po;
+
+import lombok.Data;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+
+@Data
+@Entity
+public class RelationshipPO {
+
+    @Id
+    String id;
+    String personId;
+    String leaderId;
+}

+ 82 - 0
leave-service/src/main/java/ddd/leave/domain/person/service/PersonDomainService.java

@@ -0,0 +1,82 @@
+package ddd.leave.domain.person.service;
+
+import ddd.leave.domain.person.entity.Person;
+import ddd.leave.domain.person.entity.valueobject.PersonStatus;
+import ddd.leave.domain.person.repository.facade.PersonRepository;
+import ddd.leave.domain.person.repository.po.PersonPO;
+import ddd.leave.domain.rule.service.ApprovalRuleDomainService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.Date;
+
+@Service
+@Slf4j
+public class PersonDomainService {
+
+    @Autowired
+    PersonRepository personRepository;
+    @Autowired
+    PersonFactory personFactory;
+
+
+    public void create(Person person) {
+        PersonPO personPO = personRepository.findById(person.getPersonId());
+        if (null == personPO) {
+            throw new RuntimeException("Person already exists");
+        }
+        person.create();
+        personRepository.insert(personFactory.createPersonPO(person));
+    }
+
+    public void update(Person person) {
+        person.setLastModifyTime(new Date());
+        personRepository.update(personFactory.createPersonPO(person));
+    }
+
+    public void deleteById(String personId) {
+        PersonPO personPO = personRepository.findById(personId);
+        Person person = personFactory.getPerson(personPO);
+        person.disable();
+        personRepository.update(personFactory.createPersonPO(person));
+    }
+
+    public Person findById(String userId) {
+        PersonPO personPO = personRepository.findById(userId);
+        return personFactory.getPerson(personPO);
+    }
+
+    /**
+     * find leader with applicant, if leader level bigger then leaderMaxLevel return null, else return Approver from leader;
+     *
+     * @param applicantId
+     * @param leaderMaxLevel
+     * @return
+     */
+    public Person findFirstApprover(String applicantId, int leaderMaxLevel) {
+        PersonPO leaderPO = personRepository.findLeaderByPersonId(applicantId);
+        if (leaderPO.getRoleLevel() > leaderMaxLevel) {
+            return null;
+        } else {
+            return personFactory.createPerson(leaderPO);
+        }
+    }
+
+    /**
+     * find leader with current approver, if leader level bigger then leaderMaxLevel return null, else return Approver from leader;
+     *
+     * @param currentApproverId
+     * @param leaderMaxLevel
+     * @return
+     */
+    public Person findNextApprover(String currentApproverId, int leaderMaxLevel) {
+        PersonPO leaderPO = personRepository.findLeaderByPersonId(currentApproverId);
+        if (leaderPO.getRoleLevel() > leaderMaxLevel) {
+            return null;
+        } else {
+            return personFactory.createPerson(leaderPO);
+        }
+    }
+
+}

+ 43 - 0
leave-service/src/main/java/ddd/leave/domain/person/service/PersonFactory.java

@@ -0,0 +1,43 @@
+package ddd.leave.domain.person.service;
+
+import ddd.leave.domain.person.entity.Person;
+import ddd.leave.domain.person.repository.facade.PersonRepository;
+import ddd.leave.domain.person.repository.po.PersonPO;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+@Service
+public class PersonFactory {
+
+    @Autowired
+    PersonRepository personRepository;
+
+    public PersonPO createPersonPO(Person person){
+        PersonPO personPO = new PersonPO();
+        personPO.setPersonId(person.getPersonId());
+        personPO.setPersonName(person.getPersonName());
+        personPO.setRoleLevel(person.getRoleLevel());
+        personPO.setPersonType(person.getPersonType());
+        personPO.setCreateTime(person.getCreateTime());
+        personPO.setLastModifyTime(person.getLastModifyTime());
+        return personPO;
+    }
+
+    public Person createPerson(PersonPO po){
+        Person person = new Person();
+        person.setPersonId(po.getPersonId());
+        person.setPersonType(po.getPersonType());
+        person.setRoleLevel(po.getRoleLevel());
+        person.setPersonName(po.getPersonName());
+        person.setStatus(po.getStatus());
+        person.setCreateTime(po.getCreateTime());
+        person.setLastModifyTime(po.getLastModifyTime());
+        return person;
+    }
+
+    public Person getPerson(PersonPO personPO){
+        personPO = personRepository.findById(personPO.getPersonId());
+        return createPerson(personPO);
+    }
+
+}

+ 21 - 0
leave-service/src/main/java/ddd/leave/domain/rule/entity/ApprovalRule.java

@@ -0,0 +1,21 @@
+package ddd.leave.domain.rule.entity;
+
+import ddd.leave.domain.leave.entity.Leave;
+import lombok.Data;
+
+@Data
+public class ApprovalRule {
+
+    String personType;
+    String leaveType;
+    long duration;
+    int maxLeaderLevel;
+
+    public static ApprovalRule getByLeave(Leave leave){
+        ApprovalRule rule = new ApprovalRule();
+        rule.setPersonType(leave.getApplicant().getPersonType());
+        rule.setLeaveType(leave.getType().toString());
+        rule.setDuration(leave.getDuration());
+        return rule;
+    }
+}

+ 8 - 0
leave-service/src/main/java/ddd/leave/domain/rule/repository/facade/ApprovalRuleRepositoryInterface.java

@@ -0,0 +1,8 @@
+package ddd.leave.domain.rule.repository.facade;
+
+import ddd.leave.domain.rule.entity.ApprovalRule;
+
+public interface ApprovalRuleRepositoryInterface {
+
+    int getLeaderMaxLevel(ApprovalRule rule);
+}

+ 12 - 0
leave-service/src/main/java/ddd/leave/domain/rule/repository/mapper/ApprovalRuleDao.java

@@ -0,0 +1,12 @@
+package ddd.leave.domain.rule.repository.mapper;
+
+import ddd.leave.domain.rule.entity.ApprovalRule;
+import ddd.leave.domain.rule.repository.po.ApprovalRulePO;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
+
+public interface ApprovalRuleDao extends JpaRepository<ApprovalRulePO, String> {
+
+    @Query(value = "select r from ApprovalRulePO r where r.applicantRoleId=?1 and r.leaveType=?2 and duration=?3")
+    ApprovalRule findRule(String applicantRoleId, String leaveType, long duration);
+}

+ 22 - 0
leave-service/src/main/java/ddd/leave/domain/rule/repository/persistence/ApprovalRuleRepositoryImpl.java

@@ -0,0 +1,22 @@
+package ddd.leave.domain.rule.repository.persistence;
+
+import ddd.leave.domain.rule.entity.ApprovalRule;
+import ddd.leave.domain.rule.repository.facade.ApprovalRuleRepositoryInterface;
+import ddd.leave.domain.rule.repository.mapper.ApprovalRuleDao;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public class ApprovalRuleRepositoryImpl implements ApprovalRuleRepositoryInterface {
+
+    @Autowired
+    ApprovalRuleDao ruleDao;
+
+    @Override
+    public int getLeaderMaxLevel(ApprovalRule rule) {
+        String personType = rule.getPersonType();
+        String leaveType = rule.getLeaveType();
+        rule = ruleDao.findRule(personType, leaveType, rule.getDuration());
+        return rule.getMaxLeaderLevel();
+    }
+}

+ 24 - 0
leave-service/src/main/java/ddd/leave/domain/rule/repository/po/ApprovalRulePO.java

@@ -0,0 +1,24 @@
+package ddd.leave.domain.rule.repository.po;
+
+import ddd.leave.domain.leave.entity.valueobject.LeaveType;
+import ddd.leave.domain.person.entity.valueobject.PersonType;
+import lombok.Data;
+import org.hibernate.annotations.GenericGenerator;
+
+import javax.persistence.*;
+
+@Entity
+@Data
+public class ApprovalRulePO {
+
+    @Id
+    @GenericGenerator(name = "idGenerator", strategy = "uuid")
+    @GeneratedValue(generator = "idGenerator")
+    String id;
+    @Enumerated(EnumType.STRING)
+    LeaveType leaveType;
+    @Enumerated(EnumType.STRING)
+    PersonType personType;
+    long duration;
+    String applicantRoleId;
+}

+ 21 - 0
leave-service/src/main/java/ddd/leave/domain/rule/service/ApprovalRuleDomainService.java

@@ -0,0 +1,21 @@
+package ddd.leave.domain.rule.service;
+
+import ddd.leave.domain.rule.entity.ApprovalRule;
+import ddd.leave.domain.rule.repository.facade.ApprovalRuleRepositoryInterface;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+@Service
+public class ApprovalRuleDomainService {
+
+    @Autowired
+    ApprovalRuleRepositoryInterface repositoryInterface;
+
+    public int getLeaderMaxLevel(String personType, String leaveType, long duration) {
+        ApprovalRule rule = new ApprovalRule();
+        rule.setPersonType(personType);
+        rule.setLeaveType(leaveType);
+        rule.setDuration(duration);
+        return repositoryInterface.getLeaderMaxLevel(rule);
+    }
+}

+ 13 - 0
leave-service/src/main/java/ddd/leave/infrastructure/client/AuthFeignClient.java

@@ -0,0 +1,13 @@
+package ddd.leave.infrastructure.client;
+
+import ddd.leave.domain.person.entity.Person;
+import ddd.leave.infrastructure.common.api.Response;
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.web.bind.annotation.PostMapping;
+
+@FeignClient(name = "auth-service", path = "/demo/auth")
+public interface AuthFeignClient {
+
+    @PostMapping(value = "/login")
+    Response login(Person person);
+}

+ 33 - 0
leave-service/src/main/java/ddd/leave/infrastructure/common/api/Response.java

@@ -0,0 +1,33 @@
+package ddd.leave.infrastructure.common.api;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@Builder
+public class Response {
+
+    Status status;
+    String msg;
+    Object data;
+
+    public static Response ok(){
+        return Response.builder().status(Status.SUCCESS).build();
+    }
+
+    public static Response ok(Object data){
+        return Response.builder().status(Status.SUCCESS).data(data).build();
+    }
+
+    public static Response failed(String msg){
+        return Response.builder().status(Status.FAILED).msg(msg).build();
+    }
+
+    public enum Status{
+        SUCCESS, FAILED
+    }
+}

+ 14 - 0
leave-service/src/main/java/ddd/leave/infrastructure/common/event/DomainEvent.java

@@ -0,0 +1,14 @@
+package ddd.leave.infrastructure.common.event;
+
+import lombok.Data;
+
+import java.util.Date;
+
+@Data
+public class DomainEvent {
+
+    String id;
+    Date timestamp;
+    String source;
+    String data;
+}

+ 13 - 0
leave-service/src/main/java/ddd/leave/infrastructure/common/event/EventPublisher.java

@@ -0,0 +1,13 @@
+package ddd.leave.infrastructure.common.event;
+
+import ddd.leave.domain.leave.event.LeaveEvent;
+import org.springframework.stereotype.Service;
+
+@Service
+public class EventPublisher {
+
+    public void publish(LeaveEvent event){
+        //send to MQ
+        //mq.send(event);
+    }
+}

+ 31 - 0
leave-service/src/main/java/ddd/leave/infrastructure/util/DateUtil.java

@@ -0,0 +1,31 @@
+package ddd.leave.infrastructure.util;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+public class DateUtil {
+
+    private static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";
+    private static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd hh:mm:ss";
+
+    public static Date parseDate(String dateStr) throws ParseException {
+        SimpleDateFormat sdf = new SimpleDateFormat(DEFAULT_DATE_FORMAT);
+        return sdf.parse(dateStr);
+    }
+
+    public static Date parseDateTime(String dateTimeStr) throws ParseException {
+        SimpleDateFormat sdf = new SimpleDateFormat(DEFAULT_DATE_TIME_FORMAT);
+        return sdf.parse(dateTimeStr);
+    }
+
+    public static String formatDate(Date date){
+        SimpleDateFormat sdf = new SimpleDateFormat(DEFAULT_DATE_FORMAT);
+        return sdf.format(date);
+    }
+
+    public static String formatDateTime(Date date){
+        SimpleDateFormat sdf = new SimpleDateFormat(DEFAULT_DATE_TIME_FORMAT);
+        return sdf.format(date);
+    }
+}

+ 10 - 0
leave-service/src/main/java/ddd/leave/infrastructure/util/IdGenerator.java

@@ -0,0 +1,10 @@
+package ddd.leave.infrastructure.util;
+
+import java.util.UUID;
+
+public class IdGenerator {
+
+    public static String nextId(){
+        return UUID.randomUUID().toString();
+    }
+}

+ 22 - 0
leave-service/src/main/java/ddd/leave/interfaces/assembler/ApplicantAssembler.java

@@ -0,0 +1,22 @@
+package ddd.leave.interfaces.assembler;
+
+import ddd.leave.domain.leave.entity.valueobject.Applicant;
+import ddd.leave.interfaces.dto.ApplicantDTO;
+
+public class ApplicantAssembler {
+
+    public static ApplicantDTO toDTO(Applicant applicant){
+        ApplicantDTO dto = new ApplicantDTO();
+        dto.setPersonId(applicant.getPersonId());
+        dto.setPersonName(applicant.getPersonName());
+        return dto;
+    }
+
+    public static Applicant toDO(ApplicantDTO dto){
+        Applicant applicant = new Applicant();
+        applicant.setPersonId(dto.getPersonId());
+        applicant.setPersonName(dto.getPersonName());
+        return applicant;
+    }
+
+}

+ 23 - 0
leave-service/src/main/java/ddd/leave/interfaces/assembler/ApprovalInfoAssembler.java

@@ -0,0 +1,23 @@
+package ddd.leave.interfaces.assembler;
+
+import ddd.leave.domain.leave.entity.ApprovalInfo;
+import ddd.leave.interfaces.dto.ApprovalInfoDTO;
+
+public class ApprovalInfoAssembler {
+
+    public static ApprovalInfo toDO(ApprovalInfoDTO dto){
+        ApprovalInfo approvalInfo = new ApprovalInfo();
+        approvalInfo.setApprovalInfoId(dto.getApprovalInfoId());
+        approvalInfo.setMsg(dto.getMsg());
+        approvalInfo.setApprover(ApproverAssembler.toDO(dto.getApproverDTO()));
+        return approvalInfo;
+    }
+
+    public static ApprovalInfoDTO toDTO(ApprovalInfo approvalInfo){
+        ApprovalInfoDTO dto = new ApprovalInfoDTO();
+        dto.setApprovalInfoId(approvalInfo.getApprovalInfoId());
+        dto.setMsg(approvalInfo.getMsg());
+        dto.setTime(approvalInfo.getTime());
+        return dto;
+    }
+}

+ 22 - 0
leave-service/src/main/java/ddd/leave/interfaces/assembler/ApproverAssembler.java

@@ -0,0 +1,22 @@
+package ddd.leave.interfaces.assembler;
+
+import ddd.leave.domain.leave.entity.valueobject.Approver;
+import ddd.leave.interfaces.dto.ApproverDTO;
+
+public class ApproverAssembler {
+
+    public static ApproverDTO toDTO(Approver approver){
+        ApproverDTO dto = new ApproverDTO();
+        dto.setPersonId(approver.getPersonId());
+        dto.setPersonName(approver.getPersonName());
+        return dto;
+    }
+
+    public static Approver toDO(ApproverDTO dto){
+        Approver approver = new Approver();
+        approver.setPersonId(dto.getPersonId());
+        approver.setPersonName(dto.getPersonName());
+        return approver;
+    }
+
+}

+ 45 - 0
leave-service/src/main/java/ddd/leave/interfaces/assembler/LeaveAssembler.java

@@ -0,0 +1,45 @@
+package ddd.leave.interfaces.assembler;
+
+import ddd.leave.domain.leave.entity.ApprovalInfo;
+import ddd.leave.domain.leave.entity.Leave;
+import ddd.leave.infrastructure.util.DateUtil;
+import ddd.leave.interfaces.dto.ApprovalInfoDTO;
+import ddd.leave.interfaces.dto.LeaveDTO;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class LeaveAssembler {
+
+    public static LeaveDTO toDTO(Leave leave){
+        LeaveDTO dto = new LeaveDTO();
+        dto.setLeaveId(leave.getId());
+        dto.setLeaveType(leave.getType().toString());
+        dto.setStatus(leave.getStatus().toString());
+        dto.setStartTime(DateUtil.formatDateTime(leave.getStartTime()));
+        dto.setEndTime(DateUtil.formatDateTime(leave.getEndTime()));
+        dto.setCurrentApprovalInfoDTO(ApprovalInfoAssembler.toDTO(leave.getCurrentApprovalInfo()));
+        List<ApprovalInfoDTO> historyApprovalInfoDTOList = leave.getHistoryApprovalInfos()
+                .stream()
+                .map(historyApprovalInfo -> ApprovalInfoAssembler.toDTO(leave.getCurrentApprovalInfo()))
+                .collect(Collectors.toList());
+        dto.setHistoryApprovalInfoDTOList(historyApprovalInfoDTOList);
+        dto.setDuration(leave.getDuration());
+        return dto;
+    }
+
+    public static Leave toDO(LeaveDTO dto){
+        Leave leave = new Leave();
+        leave.setId(dto.getLeaveId());
+        leave.setApplicant(ApplicantAssembler.toDO(dto.getApplicantDTO()));
+        leave.setApprover(ApproverAssembler.toDO(dto.getApproverDTO()));
+        leave.setCurrentApprovalInfo(ApprovalInfoAssembler.toDO(dto.getCurrentApprovalInfoDTO()));
+        List<ApprovalInfo> historyApprovalInfoDTOList = dto.getHistoryApprovalInfoDTOList()
+                .stream()
+                .map(historyApprovalInfoDTO -> ApprovalInfoAssembler.toDO(historyApprovalInfoDTO))
+                .collect(Collectors.toList());
+        leave.setHistoryApprovalInfos(historyApprovalInfoDTOList);
+        return leave;
+    }
+
+}

+ 34 - 0
leave-service/src/main/java/ddd/leave/interfaces/assembler/PersonAssembler.java

@@ -0,0 +1,34 @@
+package ddd.leave.interfaces.assembler;
+
+import ddd.leave.domain.person.entity.Person;
+import ddd.leave.domain.person.entity.valueobject.PersonStatus;
+import ddd.leave.domain.person.entity.valueobject.PersonType;
+import ddd.leave.infrastructure.util.DateUtil;
+import ddd.leave.interfaces.dto.PersonDTO;
+
+import java.text.ParseException;
+
+public class PersonAssembler {
+
+    public static PersonDTO toDTO(Person person){
+        PersonDTO dto = new PersonDTO();
+        dto.setPersonId(person.getPersonId());
+        dto.setPersonType(person.getPersonType().toString());
+        dto.setPersonName(person.getPersonName());
+        dto.setStatus(person.getStatus().toString());
+        dto.setCreateTime(DateUtil.formatDateTime(person.getCreateTime()));
+        dto.setLastModifyTime(DateUtil.formatDateTime(person.getLastModifyTime()));
+        return dto;
+    }
+
+    public static Person toDO(PersonDTO dto) throws ParseException {
+        Person person = new Person();
+        person.setPersonId(dto.getPersonId());
+        person.setPersonType(PersonType.valueOf(dto.getPersonType()));
+        person.setPersonName(dto.getPersonName());
+        person.setStatus(PersonStatus.valueOf(dto.getStatus()));
+        person.setCreateTime(DateUtil.parseDateTime(dto.getCreateTime()));
+        person.setLastModifyTime(DateUtil.parseDateTime(dto.getLastModifyTime()));
+        return person;
+    }
+}

+ 13 - 0
leave-service/src/main/java/ddd/leave/interfaces/dto/ApplicantDTO.java

@@ -0,0 +1,13 @@
+package ddd.leave.interfaces.dto;
+
+import lombok.Data;
+
+@Data
+public class ApplicantDTO {
+
+    String personId;
+    String personName;
+    String leaderId;
+    String applicantType;
+    String roleLevel;
+}

+ 12 - 0
leave-service/src/main/java/ddd/leave/interfaces/dto/ApprovalInfoDTO.java

@@ -0,0 +1,12 @@
+package ddd.leave.interfaces.dto;
+
+import lombok.Data;
+
+@Data
+public class ApprovalInfoDTO {
+
+    String approvalInfoId;
+    ApproverDTO approverDTO;
+    String msg;
+    long time;
+}

+ 9 - 0
leave-service/src/main/java/ddd/leave/interfaces/dto/ApproverDTO.java

@@ -0,0 +1,9 @@
+package ddd.leave.interfaces.dto;
+
+import lombok.Data;
+
+@Data
+public class ApproverDTO {
+    String personId;
+    String personName;
+}

+ 21 - 0
leave-service/src/main/java/ddd/leave/interfaces/dto/LeaveDTO.java

@@ -0,0 +1,21 @@
+package ddd.leave.interfaces.dto;
+
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class LeaveDTO {
+
+    String leaveId;
+    ApplicantDTO applicantDTO;
+    ApproverDTO approverDTO;
+    String leaveType;
+    ApprovalInfoDTO currentApprovalInfoDTO;
+    List<ApprovalInfoDTO> historyApprovalInfoDTOList;
+    String startTime;
+    String endTime;
+    long duration;
+    String status;
+
+}

+ 15 - 0
leave-service/src/main/java/ddd/leave/interfaces/dto/PersonDTO.java

@@ -0,0 +1,15 @@
+package ddd.leave.interfaces.dto;
+
+import lombok.Data;
+
+@Data
+public class PersonDTO {
+
+    String personId;
+    String personName;
+    String roleId;
+    String personType;
+    String createTime;
+    String lastModifyTime;
+    String status;
+}

+ 28 - 0
leave-service/src/main/java/ddd/leave/interfaces/facade/AuthApi.java

@@ -0,0 +1,28 @@
+package ddd.leave.interfaces.facade;
+
+import ddd.leave.application.service.LoginApplicationService;
+import ddd.leave.domain.person.entity.Person;
+import ddd.leave.infrastructure.common.api.Response;
+import ddd.leave.interfaces.assembler.LeaveAssembler;
+import ddd.leave.interfaces.assembler.PersonAssembler;
+import ddd.leave.interfaces.dto.LeaveDTO;
+import ddd.leave.interfaces.dto.PersonDTO;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping("/auth")
+@Slf4j
+public class AuthApi {
+
+    @Autowired
+    LoginApplicationService loginApplicationService;
+
+    @PostMapping("/login")
+    public Response login(PersonDTO personDTO){
+        return loginApplicationService.login(PersonAssembler.toDO(personDTO));
+    }
+}

+ 74 - 0
leave-service/src/main/java/ddd/leave/interfaces/facade/LeaveApi.java

@@ -0,0 +1,74 @@
+package ddd.leave.interfaces.facade;
+
+import ddd.leave.application.service.LeaveApplicationService;
+import ddd.leave.domain.leave.entity.Leave;
+import ddd.leave.domain.person.entity.Person;
+import ddd.leave.infrastructure.common.api.Response;
+import ddd.leave.interfaces.assembler.LeaveAssembler;
+import ddd.leave.interfaces.dto.LeaveDTO;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+@RestController
+@RequestMapping("/leave")
+@Slf4j
+public class LeaveApi {
+
+    @Autowired
+    LeaveApplicationService leaveApplicationService;
+
+    @PostMapping
+    public Response createLeaveInfo(LeaveDTO leaveDTO){
+        Leave leave = LeaveAssembler.toDO(leaveDTO);
+        leaveApplicationService.createLeaveInfo(leave);
+        return Response.ok();
+    }
+
+    @PutMapping
+    public Response updateLeaveInfo(LeaveDTO leaveDTO){
+        Leave leave = LeaveAssembler.toDO(leaveDTO);
+        leaveApplicationService.updateLeaveInfo(leave);
+        return Response.ok();
+    }
+
+    @PostMapping("/submit")
+    public Response submitApproval(LeaveDTO leaveDTO){
+        Leave leave = LeaveAssembler.toDO(leaveDTO);
+        leaveApplicationService.submitApproval(leave);
+        return Response.ok();
+    }
+
+    @PostMapping("/{leaveId}")
+    public Response findById(@PathVariable String leaveId){
+        Leave leave = leaveApplicationService.getLeaveInfo(leaveId);
+        return Response.ok(LeaveAssembler.toDTO(leave));
+    }
+
+    /**
+     * 根据申请人查询所有请假单
+     * @param applicantId
+     * @return
+     */
+    @PostMapping("/query/applicant/{applicantId}")
+    public Response queryByApplicant(@PathVariable String applicantId){
+        List<Leave> leaveList = leaveApplicationService.queryLeaveInfosByApplicant(applicantId);
+        List<LeaveDTO> leaveDTOList = leaveList.stream().map(leave -> LeaveAssembler.toDTO(leave)).collect(Collectors.toList());
+        return Response.ok(leaveDTOList);
+    }
+
+    /**
+     * 根据审批人id查询待审批请假单(待办任务)
+     * @param approverId
+     * @return
+     */
+    @PostMapping("/query/approver/{approverId}")
+    public Response queryByApprover(@PathVariable String approverId){
+        List<Leave> leaveList = leaveApplicationService.queryLeaveInfosByApprover(approverId);
+        List<LeaveDTO> leaveDTOList = leaveList.stream().map(leave -> LeaveAssembler.toDTO(leave)).collect(Collectors.toList());
+        return Response.ok(leaveDTOList);
+    }
+}

+ 62 - 0
leave-service/src/main/java/ddd/leave/interfaces/facade/PersonApi.java

@@ -0,0 +1,62 @@
+package ddd.leave.interfaces.facade;
+
+import ddd.leave.application.service.PersonApplicationService;
+import ddd.leave.domain.person.entity.Person;
+import ddd.leave.infrastructure.common.api.Response;
+import ddd.leave.interfaces.assembler.PersonAssembler;
+import ddd.leave.interfaces.dto.PersonDTO;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.text.ParseException;
+
+@RestController
+@RequestMapping("/person")
+@Slf4j
+public class PersonApi {
+
+    @Autowired
+    PersonApplicationService personApplicationService;
+
+    @PostMapping
+    public Response create(PersonDTO personDTO) {
+        try {
+            personApplicationService.create(PersonAssembler.toDO(personDTO));
+            return Response.ok();
+        } catch (ParseException e) {
+            log.error("", e);
+            return Response.failed(e.getMessage());
+        }
+    }
+
+    @PutMapping
+    public Response update(PersonDTO personDTO) {
+        try {
+            personApplicationService.update(PersonAssembler.toDO(personDTO));
+        } catch (ParseException e) {
+            log.error("", e);
+            return Response.failed(e.getMessage());
+        }
+        return Response.ok();
+    }
+
+    @DeleteMapping("/{personId}")
+    public Response delete(@PathVariable String personId) {
+        personApplicationService.deleteById(personId);
+        return Response.ok();
+    }
+
+    @GetMapping("/{personId}")
+    public Response get(@PathVariable String personId) {
+        Person person = personApplicationService.findById(personId);
+        return Response.ok(PersonAssembler.toDTO(person));
+    }
+
+    @GetMapping("/findFirstApprover")
+    public Response findFirstApprover(@RequestParam String applicantId, @RequestParam int leaderMaxLevel) {
+        Person person = personApplicationService.findFirstApprover(applicantId, leaderMaxLevel);
+        return Response.ok(PersonAssembler.toDTO(person));
+    }
+
+}

+ 14 - 0
leave-service/src/main/resources/application.yml

@@ -0,0 +1,14 @@
+spring:
+  datasource:
+    driver-class-name: org.postgresql.Driver
+    url: jdbc:postgresql://localhost:5432/leave
+    username: leave
+    password: leave
+  jpa:
+    hibernate:
+      ddl-auto: update
+    properties:
+      hibernate:
+        temp:
+          use_jdbc_metadata_defaults: false
+    show-sql: true