Browse Source

UAS集成优软云平台

yingp 5 years ago
commit
e6c1bd1912
100 changed files with 10391 additions and 0 deletions
  1. 33 0
      .gitignore
  2. 32 0
      README.md
  3. BIN
      docs/UAS对接B2B-SDK测试报告.docx
  4. 131 0
      pom.xml
  5. 24 0
      uas-pl-b2b/pom.xml
  6. 22 0
      uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/agent/PurchaseChangeAgent.java
  7. 22 0
      uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/config/B2bConfig.java
  8. 29 0
      uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/config/B2bProperties.java
  9. 118 0
      uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/config/B2bSdk.java
  10. 14 0
      uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/exception/ResponseError.java
  11. 65 0
      uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/po/AcceptNotifyConfirmPO.java
  12. 111 0
      uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/po/AcceptNotifyDetailPO.java
  13. 172 0
      uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/po/AcceptNotifyPO.java
  14. 115 0
      uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/po/AcceptNotifyVerifyPO.java
  15. 88 0
      uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/po/AttachPO.java
  16. 196 0
      uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/po/PurchaseBillDetailPO.java
  17. 306 0
      uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/po/PurchaseBillPO.java
  18. 164 0
      uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/po/PurchaseChangeDetailPO.java
  19. 256 0
      uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/po/PurchaseChangePO.java
  20. 63 0
      uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/po/PurchaseDetailEndPO.java
  21. 464 0
      uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/po/PurchaseDetailPO.java
  22. 181 0
      uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/po/PurchaseNotifyPO.java
  23. 445 0
      uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/po/PurchasePO.java
  24. 173 0
      uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/po/PurchaseProdInOutDetailPO.java
  25. 269 0
      uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/po/PurchaseProdInOutPO.java
  26. 150 0
      uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/po/PurchaseReplyPO.java
  27. 173 0
      uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/po/SaleCheckDetailPO.java
  28. 275 0
      uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/po/SaleCheckPO.java
  29. 86 0
      uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/po/SaleDownChangeReplyPO.java
  30. 86 0
      uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/po/SaleOutDetailPO.java
  31. 170 0
      uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/po/SaleOutPO.java
  32. 165 0
      uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/po/SaleReplyPO.java
  33. 51 0
      uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/service/AbstractB2bService.java
  34. 67 0
      uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/service/PurchaseBillService.java
  35. 77 0
      uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/service/PurchaseChangeService.java
  36. 133 0
      uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/service/PurchaseCheckService.java
  37. 95 0
      uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/service/PurchaseInOutService.java
  38. 306 0
      uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/service/PurchaseNotifyService.java
  39. 189 0
      uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/service/PurchaseService.java
  40. 154 0
      uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/service/SaleBillService.java
  41. 199 0
      uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/service/SaleChangeService.java
  42. 149 0
      uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/service/SaleNotifyService.java
  43. 267 0
      uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/service/SaleService.java
  44. 24 0
      uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/task/AbstractB2bTask.java
  45. 59 0
      uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/task/PurchaseBillTask.java
  46. 98 0
      uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/task/PurchaseChangeTask.java
  47. 76 0
      uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/task/PurchaseCheckTask.java
  48. 103 0
      uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/task/PurchaseInOutTask.java
  49. 221 0
      uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/task/PurchaseNotifyTask.java
  50. 153 0
      uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/task/PurchaseTask.java
  51. 59 0
      uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/task/SaleBillTask.java
  52. 111 0
      uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/task/SaleChangeTask.java
  53. 145 0
      uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/task/SaleNotifyTask.java
  54. 139 0
      uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/task/SaleTask.java
  55. 32 0
      uas-pl-core/pom.xml
  56. 72 0
      uas-pl-core/src/main/java/com/usoftchina/uas/pl/agent/AbstractUasAgent.java
  57. 24 0
      uas-pl-core/src/main/java/com/usoftchina/uas/pl/context/ContextHolder.java
  58. 38 0
      uas-pl-core/src/main/java/com/usoftchina/uas/pl/context/MasterHolder.java
  59. 56 0
      uas-pl-core/src/main/java/com/usoftchina/uas/pl/controller/MasterController.java
  60. 40 0
      uas-pl-core/src/main/java/com/usoftchina/uas/pl/crypto/Hex.java
  61. 97 0
      uas-pl-core/src/main/java/com/usoftchina/uas/pl/crypto/HmacEncoder.java
  62. 9 0
      uas-pl-core/src/main/java/com/usoftchina/uas/pl/crypto/HmacSHA256Encoder.java
  63. 23 0
      uas-pl-core/src/main/java/com/usoftchina/uas/pl/dto/PageDefault.java
  64. 54 0
      uas-pl-core/src/main/java/com/usoftchina/uas/pl/dto/PageRequest.java
  65. 94 0
      uas-pl-core/src/main/java/com/usoftchina/uas/pl/dto/PageRequestArgumentResolver.java
  66. 33 0
      uas-pl-core/src/main/java/com/usoftchina/uas/pl/dto/Paging.java
  67. 120 0
      uas-pl-core/src/main/java/com/usoftchina/uas/pl/dto/Result.java
  68. 86 0
      uas-pl-core/src/main/java/com/usoftchina/uas/pl/entity/DataCenter.java
  69. 14 0
      uas-pl-core/src/main/java/com/usoftchina/uas/pl/entity/KeyEntity.java
  70. 194 0
      uas-pl-core/src/main/java/com/usoftchina/uas/pl/entity/Master.java
  71. 46 0
      uas-pl-core/src/main/java/com/usoftchina/uas/pl/event/DataCenterEvents.java
  72. 23 0
      uas-pl-core/src/main/java/com/usoftchina/uas/pl/event/MasterChangedEvent.java
  73. 8 0
      uas-pl-core/src/main/java/com/usoftchina/uas/pl/exception/EmptyMasterException.java
  74. 46 0
      uas-pl-core/src/main/java/com/usoftchina/uas/pl/jdbc/DataSourceBean.java
  75. 36 0
      uas-pl-core/src/main/java/com/usoftchina/uas/pl/jdbc/DataSourceHolder.java
  76. 162 0
      uas-pl-core/src/main/java/com/usoftchina/uas/pl/jdbc/DynamicDataSource.java
  77. 81 0
      uas-pl-core/src/main/java/com/usoftchina/uas/pl/jdbc/DynamicDataSourceConfig.java
  78. 46 0
      uas-pl-core/src/main/java/com/usoftchina/uas/pl/jdbc/DynamicDataSourceRegister.java
  79. 306 0
      uas-pl-core/src/main/java/com/usoftchina/uas/pl/jdbc/SchemaUtils.java
  80. 92 0
      uas-pl-core/src/main/java/com/usoftchina/uas/pl/jdbc/Transaction.java
  81. 72 0
      uas-pl-core/src/main/java/com/usoftchina/uas/pl/service/AbstractService.java
  82. 47 0
      uas-pl-core/src/main/java/com/usoftchina/uas/pl/service/DataCenterService.java
  83. 113 0
      uas-pl-core/src/main/java/com/usoftchina/uas/pl/service/MasterService.java
  84. 51 0
      uas-pl-core/src/main/java/com/usoftchina/uas/pl/service/SchemaService.java
  85. 8 0
      uas-pl-core/src/main/java/com/usoftchina/uas/pl/utils/CollectionUtils.java
  86. 26 0
      uas-pl-core/src/main/java/com/usoftchina/uas/pl/utils/Const.java
  87. 76 0
      uas-pl-core/src/main/java/com/usoftchina/uas/pl/utils/DateUtils.java
  88. 50 0
      uas-pl-core/src/main/java/com/usoftchina/uas/pl/utils/HmacUtils.java
  89. 19 0
      uas-pl-core/src/main/java/com/usoftchina/uas/pl/utils/NumberUtils.java
  90. 137 0
      uas-pl-core/src/main/java/com/usoftchina/uas/pl/utils/Status.java
  91. 35 0
      uas-pl-core/src/main/java/com/usoftchina/uas/pl/utils/StringUtils.java
  92. 22 0
      uas-pl-finance/pom.xml
  93. 24 0
      uas-pl-product/pom.xml
  94. 22 0
      uas-pl-product/src/main/java/com/usoftchina/uas/pl/product/config/ProductConfig.java
  95. 29 0
      uas-pl-product/src/main/java/com/usoftchina/uas/pl/product/config/ProductProperties.java
  96. 42 0
      uas-pl-product/src/main/java/com/usoftchina/uas/pl/product/config/Sdk.java
  97. 14 0
      uas-pl-product/src/main/java/com/usoftchina/uas/pl/product/exception/ResponseError.java
  98. 244 0
      uas-pl-product/src/main/java/com/usoftchina/uas/pl/product/po/ProductPO.java
  99. 31 0
      uas-pl-product/src/main/java/com/usoftchina/uas/pl/product/service/ProductService.java
  100. 24 0
      uas-pl-product/src/main/java/com/usoftchina/uas/pl/product/task/AbstractProductTask.java

+ 33 - 0
.gitignore

@@ -0,0 +1,33 @@
+.git
+logs
+rebel.xml
+target
+out
+!.mvn/wrapper/maven-wrapper.jar
+### VSCODE ###
+.vscode
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+
+### IntelliJ IDEA ###
+.gradle
+.idea
+*.iws
+*.iml
+*.ipr
+
+### NetBeans ###
+nbproject/private/
+nbbuild/
+dist/
+node_modules/
+nbdist/
+.nb-gradle/
+generatorConfig.xml
+
+*.log:

+ 32 - 0
README.md

@@ -0,0 +1,32 @@
+## 项目说明
+
+- 用于对接各个平台
+- 提供了可在线配置数据源的工具
+- 提供了可在线配置的度任务的框架
+
+## 项目结构
+
+```
+├─uas-pl-integration
+│  │  
+│  ├─docs-------------------------------------文档
+│  ├─uas-pl-b2b-------------------------------对接B2B业务
+│  ├─uas-pl-core------------------------------基础包
+│  ├─uas-pl-finance---------------------------对接金融业务
+│  ├─uas-pl-product---------------------------对接物料业务
+│  ├─uas-pl-server----------------------------服务端
+│  ├─uas-pl-task------------------------------调度任务包
+│  ├─uas-pl-web-------------------------------前端web
+│  │
+```
+
+## 对接
+
+- 业务对接可以参考uas-pl-b2b
+- b2b-sdk文档 https://document.usoftchina.com/b2b
+- b2b-sdk仓库 https://github.com/usoft-china/usoft-sdk-b2b
+
+## 发布
+
+- 先构建uas-pl-web,生成的文件复制到uas-pl-server/src/main/resources/static下,然后编译uas-pl-server
+

BIN
docs/UAS对接B2B-SDK测试报告.docx


+ 131 - 0
pom.xml

@@ -0,0 +1,131 @@
+<?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>com.usoftchina.uas</groupId>
+    <artifactId>uas-pl-integration</artifactId>
+    <packaging>pom</packaging>
+    <version>1.0-SNAPSHOT</version>
+    <modules>
+        <module>uas-pl-core</module>
+        <module>uas-pl-task</module>
+        <module>uas-pl-b2b</module>
+        <module>uas-pl-server</module>
+        <module>uas-pl-finance</module>
+        <module>uas-pl-product</module>
+    </modules>
+
+    <properties>
+        <spring.boot.version>2.1.4.RELEASE</spring.boot.version>
+        <fastjson.version>1.2.47</fastjson.version>
+        <b2b.sdk.version>1.0</b2b.sdk.version>
+        <ojdbc.version>11.2.0</ojdbc.version>
+    </properties>
+
+    <repositories>
+        <repository>
+            <snapshots>
+                <enabled>false</enabled>
+            </snapshots>
+            <id>uuzcc-release</id>
+            <name>uuzcc-release</name>
+            <url>https://artifactory.uuzcc.cn/artifactory/libs-release</url>
+        </repository>
+        <repository>
+            <snapshots />
+            <id>uuzcc-snapshot</id>
+            <name>uuzcc-snapshot</name>
+            <url>https://artifactory.uuzcc.cn/artifactory/libs-snapshot</url>
+        </repository>
+        <repository>
+            <snapshots>
+                <enabled>false</enabled>
+            </snapshots>
+            <id>aliyun</id>
+            <name>aliyun</name>
+            <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
+        </repository>
+        <repository>
+            <snapshots>
+                <enabled>false</enabled>
+            </snapshots>
+            <id>ubtob-release</id>
+            <name>ubtob-release</name>
+            <url>http://maven.ubtob.com/artifactory/libs-release-local</url>
+        </repository>
+        <repository>
+            <snapshots />
+            <id>ubtob-snapshot</id>
+            <name>ubtob-snapshot</name>
+            <url>http://maven.ubtob.com/artifactory/libs-snapshot-local</url>
+        </repository>
+        <repository>
+            <snapshots>
+                <enabled>false</enabled>
+            </snapshots>
+            <id>spring</id>
+            <name>spring-milestone</name>
+            <url>https://repo.spring.io/libs-milestone</url>
+        </repository>
+    </repositories>
+
+    <dependencyManagement>
+        <dependencies>
+            <dependency>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-dependencies</artifactId>
+                <version>${spring.boot.version}</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+            <dependency>
+                <groupId>com.usoftchina.uas</groupId>
+                <artifactId>uas-pl-core</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>com.usoftchina.uas</groupId>
+                <artifactId>uas-pl-task</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>com.usoftchina.uas</groupId>
+                <artifactId>uas-pl-b2b</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>com.usoftchina.uas</groupId>
+                <artifactId>uas-pl-product</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>com.alibaba</groupId>
+                <artifactId>fastjson</artifactId>
+                <version>${fastjson.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>com.usoft.sdk</groupId>
+                <artifactId>usoft-sdk-b2b</artifactId>
+                <version>${b2b.sdk.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>com.oracle</groupId>
+                <artifactId>ojdbc6</artifactId>
+                <version>${ojdbc.version}</version>
+            </dependency>
+        </dependencies>
+    </dependencyManagement>
+
+    <distributionManagement>
+        <repository>
+            <id>libs-release-local</id>
+            <url>http://maven.ubtob.com/artifactory/libs-release-local</url>
+        </repository>
+        <snapshotRepository>
+            <id>libs-snapshot-local</id>
+            <url>http://maven.ubtob.com/artifactory/libs-snapshot-local</url>
+        </snapshotRepository>
+    </distributionManagement>
+</project>

+ 24 - 0
uas-pl-b2b/pom.xml

@@ -0,0 +1,24 @@
+<?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">
+    <parent>
+        <artifactId>uas-pl-integration</artifactId>
+        <groupId>com.usoftchina.uas</groupId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>uas-pl-b2b</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.usoftchina.uas</groupId>
+            <artifactId>uas-pl-task</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.usoft.sdk</groupId>
+            <artifactId>usoft-sdk-b2b</artifactId>
+        </dependency>
+    </dependencies>
+</project>

+ 22 - 0
uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/agent/PurchaseChangeAgent.java

@@ -0,0 +1,22 @@
+package com.usoftchina.uas.pl.b2b.agent;
+
+import com.usoftchina.uas.pl.agent.AbstractUasAgent;
+import org.springframework.stereotype.Service;
+import org.springframework.ui.ModelMap;
+
+/**
+ * @author yingp
+ * @date 2020/1/18
+ */
+@Service
+public class PurchaseChangeAgent extends AbstractUasAgent {
+
+    /**
+     * 采购变更单同意
+     *
+     * @param code 变更单号
+     */
+    public boolean agree(String code) {
+        return postForEntity("/scm/purchase/agreePurchaseChange.action", new ModelMap("code", code));
+    }
+}

+ 22 - 0
uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/config/B2bConfig.java

@@ -0,0 +1,22 @@
+package com.usoftchina.uas.pl.b2b.config;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * @author yingp
+ * @date 2020/1/13
+ */
+@Configuration
+@EnableConfigurationProperties(B2bProperties.class)
+public class B2bConfig {
+    @Autowired
+    private B2bProperties properties;
+
+    @Bean
+    public B2bSdk b2bSdk() {
+        return new B2bSdk(properties);
+    }
+}

+ 29 - 0
uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/config/B2bProperties.java

@@ -0,0 +1,29 @@
+package com.usoftchina.uas.pl.b2b.config;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+/**
+ * @author yingp
+ * @date 2020/1/13
+ */
+@ConfigurationProperties(prefix = "b2b")
+public class B2bProperties {
+    private String url = "http://b2b-api.usoftchina.com";
+    private String testUrl = "http://test-b2b.uuzcc.cn";
+
+    public String getUrl() {
+        return url;
+    }
+
+    public void setUrl(String url) {
+        this.url = url;
+    }
+
+    public String getTestUrl() {
+        return testUrl;
+    }
+
+    public void setTestUrl(String testUrl) {
+        this.testUrl = testUrl;
+    }
+}

+ 118 - 0
uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/config/B2bSdk.java

@@ -0,0 +1,118 @@
+package com.usoftchina.uas.pl.b2b.config;
+
+import com.usoft.sdk.b2b.client.*;
+import com.usoftchina.uas.pl.context.MasterHolder;
+import com.usoftchina.uas.pl.entity.Master;
+import com.usoftchina.uas.pl.exception.EmptyMasterException;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * sdk封装
+ *
+ * @author yingp
+ * @date 2020/1/13
+ */
+public class B2bSdk {
+    /**
+     * 送货
+     */
+    private final static Map<Master, DeliverSdk> deliverSdkMap = new ConcurrentHashMap<>();
+    /**
+     * 发票
+     */
+    private final static Map<Master, InvoiceSdk> invoiceSdkMap = new ConcurrentHashMap<>();
+    /**
+     * 订单
+     */
+    private final static Map<Master, OrderSdk> orderSdkMap = new ConcurrentHashMap<>();
+    /**
+     * 物料
+     */
+    private final static Map<Master, ProductSdk> productSdkMap = new ConcurrentHashMap<>();
+    /**
+     * 对账
+     */
+    private final static Map<Master, ReconciliationSdk> reconciliationSdkMap = new ConcurrentHashMap<>();
+    private final B2bProperties properties;
+
+    public B2bSdk(B2bProperties properties) {
+        this.properties = properties;
+    }
+
+    public DeliverSdk deliver() {
+        Master master = MasterHolder.get();
+        if (null == master) {
+            throw new EmptyMasterException();
+        }
+        if (!deliverSdkMap.containsKey(master)) {
+            DeliverSdk sdk = new DeliverSdk(
+                    master.wasTest() ? properties.getTestUrl() : properties.getUrl(),
+                    String.valueOf(master.getMa_uu()), master.getMa_accesssecret());
+            deliverSdkMap.put(master, sdk);
+            return sdk;
+        }
+        return deliverSdkMap.get(master);
+    }
+
+    public InvoiceSdk invoice() {
+        Master master = MasterHolder.get();
+        if (null == master) {
+            throw new EmptyMasterException();
+        }
+        if (!invoiceSdkMap.containsKey(master)) {
+            InvoiceSdk sdk = new InvoiceSdk(
+                    master.wasTest() ? properties.getTestUrl() : properties.getUrl(),
+                    String.valueOf(master.getMa_uu()), master.getMa_accesssecret());
+            invoiceSdkMap.put(master, sdk);
+            return sdk;
+        }
+        return invoiceSdkMap.get(master);
+    }
+
+    public OrderSdk order() {
+        Master master = MasterHolder.get();
+        if (null == master) {
+            throw new EmptyMasterException();
+        }
+        if (!orderSdkMap.containsKey(master)) {
+            OrderSdk sdk = new OrderSdk(
+                    master.wasTest() ? properties.getTestUrl() : properties.getUrl(),
+                    String.valueOf(master.getMa_uu()), master.getMa_accesssecret());
+            orderSdkMap.put(master, sdk);
+            return sdk;
+        }
+        return orderSdkMap.get(master);
+    }
+
+    public ProductSdk product() {
+        Master master = MasterHolder.get();
+        if (null == master) {
+            throw new EmptyMasterException();
+        }
+        if (!productSdkMap.containsKey(master)) {
+            ProductSdk sdk = new ProductSdk(
+                    master.wasTest() ? properties.getTestUrl() : properties.getUrl(),
+                    String.valueOf(master.getMa_uu()), master.getMa_accesssecret());
+            productSdkMap.put(master, sdk);
+            return sdk;
+        }
+        return productSdkMap.get(master);
+    }
+
+    public ReconciliationSdk reconciliation() {
+        Master master = MasterHolder.get();
+        if (null == master) {
+            throw new EmptyMasterException();
+        }
+        if (!reconciliationSdkMap.containsKey(master)) {
+            ReconciliationSdk sdk = new ReconciliationSdk(
+                    master.wasTest() ? properties.getTestUrl() : properties.getUrl(),
+                    String.valueOf(master.getMa_uu()), master.getMa_accesssecret());
+            reconciliationSdkMap.put(master, sdk);
+            return sdk;
+        }
+        return reconciliationSdkMap.get(master);
+    }
+}

+ 14 - 0
uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/exception/ResponseError.java

@@ -0,0 +1,14 @@
+package com.usoftchina.uas.pl.b2b.exception;
+
+import com.usoft.b2b.external.api.entity.RespHeader;
+
+/**
+ * @author yingp
+ * @date 2020/1/15
+ */
+public class ResponseError extends RuntimeException{
+
+    public ResponseError(RespHeader header) {
+        super(String.format("code %s, msg: %s", header.getCode(), header.getMsg()));
+    }
+}

+ 65 - 0
uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/po/AcceptNotifyConfirmPO.java

@@ -0,0 +1,65 @@
+package com.usoftchina.uas.pl.b2b.po;
+
+import com.usoft.b2b.external.erp.deliver.api.entity.AcceptNotifyConfirm;
+import com.usoftchina.uas.pl.entity.KeyEntity;
+import com.usoftchina.uas.pl.utils.NumberUtils;
+
+/**
+ * @author yingp
+ */
+public class AcceptNotifyConfirmPO implements KeyEntity {
+
+    private Long and_id;
+    private Long b2b_ss_id;
+    private short and_detno;
+    private Double and_inqty;
+
+    public Long getAnd_id() {
+        return and_id;
+    }
+
+    public void setAnd_id(Long and_id) {
+        this.and_id = and_id;
+    }
+
+    public Long getB2b_ss_id() {
+        return b2b_ss_id;
+    }
+
+    public void setB2b_ss_id(Long b2b_ss_id) {
+        this.b2b_ss_id = b2b_ss_id;
+    }
+
+    public short getAnd_detno() {
+        return and_detno;
+    }
+
+    public void setAnd_detno(short and_detno) {
+        this.and_detno = and_detno;
+    }
+
+    public Double getAnd_inqty() {
+        return and_inqty;
+    }
+
+    public void setAnd_inqty(Double and_inqty) {
+        this.and_inqty = and_inqty;
+    }
+
+    public AcceptNotifyConfirm map() {
+        AcceptNotifyConfirm.Builder builder = AcceptNotifyConfirm.newBuilder();
+        if (!NumberUtils.isEmpty(b2b_ss_id)) {
+            builder.setB2BSsId(b2b_ss_id);
+        }
+        builder.setAndDetno(and_detno);
+        if (null != and_inqty) {
+            builder.setAndInqty(and_inqty);
+        }
+        return builder.build();
+    }
+
+    @Override
+    public Object id() {
+        return and_id;
+    }
+}

+ 111 - 0
uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/po/AcceptNotifyDetailPO.java

@@ -0,0 +1,111 @@
+package com.usoftchina.uas.pl.b2b.po;
+
+import com.usoft.b2b.external.erp.deliver.api.entity.AcceptNotify;
+import com.usoftchina.uas.pl.utils.NumberUtils;
+import com.usoftchina.uas.pl.utils.StringUtils;
+
+/**
+ * 收料通知单明细
+ * 
+ * @author yingp
+ * 
+ */
+public class AcceptNotifyDetailPO {
+
+	private short and_detno;
+	private String and_ordercode;
+	private Short and_orderdetno;
+	private Long and_pnid;
+	private Double and_inqty;
+	private Double and_price;
+	private String and_remark;
+	private Long and_id;
+
+	public short getAnd_detno() {
+		return and_detno;
+	}
+
+	public void setAnd_detno(short and_detno) {
+		this.and_detno = and_detno;
+	}
+
+	public String getAnd_ordercode() {
+		return and_ordercode;
+	}
+
+	public void setAnd_ordercode(String and_ordercode) {
+		this.and_ordercode = and_ordercode;
+	}
+
+	public Short getAnd_orderdetno() {
+		return and_orderdetno;
+	}
+
+	public void setAnd_orderdetno(Short and_orderdetno) {
+		this.and_orderdetno = and_orderdetno;
+	}
+
+	public Double getAnd_inqty() {
+		return and_inqty;
+	}
+
+	public void setAnd_inqty(Double and_inqty) {
+		this.and_inqty = and_inqty;
+	}
+
+	public Long getAnd_pnid() {
+		return and_pnid;
+	}
+
+	public void setAnd_pnid(Long and_pnid) {
+		this.and_pnid = and_pnid;
+	}
+
+	public String getAnd_remark() {
+		return and_remark;
+	}
+
+	public void setAnd_remark(String and_remark) {
+		this.and_remark = and_remark;
+	}
+
+	public Double getAnd_price() {
+		return and_price;
+	}
+
+	public void setAnd_price(Double and_price) {
+		this.and_price = and_price;
+	}
+
+	public Long getAnd_id() {
+		return and_id;
+	}
+
+	public void setAnd_id(Long and_id) {
+		this.and_id = and_id;
+	}
+
+	public AcceptNotify.AcceptNotifyDetail map() {
+		AcceptNotify.AcceptNotifyDetail.Builder builder = AcceptNotify.AcceptNotifyDetail.newBuilder();
+		if (!StringUtils.isEmpty(and_ordercode)) {
+			builder.setAndOrdercode(and_ordercode);
+		}
+		if (null != and_orderdetno) {
+			builder.setAndOrderdetno(and_orderdetno);
+		}
+		if (!NumberUtils.isEmpty(and_pnid)) {
+			builder.setAndPnid(and_pnid);
+		}
+		if (null != and_inqty) {
+			builder.setAndInqty(and_inqty);
+		}
+		if (null != and_price) {
+			builder.setAndPrice(and_price);
+		}
+		if (!StringUtils.isEmpty(and_remark)) {
+			builder.setAndRemark(and_remark);
+		}
+		builder.setAndDetno(and_detno);
+		return builder.build();
+	}
+}

+ 172 - 0
uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/po/AcceptNotifyPO.java

@@ -0,0 +1,172 @@
+package com.usoftchina.uas.pl.b2b.po;
+
+import com.usoft.b2b.external.erp.deliver.api.entity.AcceptNotify;
+import com.usoftchina.uas.pl.entity.KeyEntity;
+import com.usoftchina.uas.pl.utils.NumberUtils;
+import com.usoftchina.uas.pl.utils.StringUtils;
+import org.springframework.util.CollectionUtils;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 买家ERP的收料通知单
+ *
+ * @author yingp
+ */
+public class AcceptNotifyPO implements KeyEntity {
+
+	/**
+	 * 平台上的发货单ID
+	 */
+	private Long b2b_ss_id;
+	private Integer an_id;
+	private long an_venduu;
+	private String an_currency;
+	private Float an_rate;
+	private String an_payment;
+	private Long an_buyeruu;
+	private String an_sendcode;
+	private String an_recorder;
+	private String an_remark;
+	private Date an_date;
+	private List<AcceptNotifyDetailPO> details;
+
+	public Long getB2b_ss_id() {
+		return b2b_ss_id;
+	}
+
+	public void setB2b_ss_id(Long b2b_ss_id) {
+		this.b2b_ss_id = b2b_ss_id;
+	}
+
+	public Integer getAn_id() {
+		return an_id;
+	}
+
+	public void setAn_id(Integer an_id) {
+		this.an_id = an_id;
+	}
+
+	public long getAn_venduu() {
+		return an_venduu;
+	}
+
+	public void setAn_venduu(long an_venduu) {
+		this.an_venduu = an_venduu;
+	}
+
+	public String getAn_currency() {
+		return an_currency;
+	}
+
+	public void setAn_currency(String an_currency) {
+		this.an_currency = an_currency;
+	}
+
+	public Float getAn_rate() {
+		return an_rate;
+	}
+
+	public void setAn_rate(Float an_rate) {
+		this.an_rate = an_rate;
+	}
+
+	public String getAn_payment() {
+		return an_payment;
+	}
+
+	public void setAn_payment(String an_payment) {
+		this.an_payment = an_payment;
+	}
+
+	public Long getAn_buyeruu() {
+		return an_buyeruu;
+	}
+
+	public void setAn_buyeruu(Long an_buyeruu) {
+		this.an_buyeruu = an_buyeruu;
+	}
+
+	public String getAn_sendcode() {
+		return an_sendcode;
+	}
+
+	public void setAn_sendcode(String an_sendcode) {
+		this.an_sendcode = an_sendcode;
+	}
+
+	public String getAn_recorder() {
+		return an_recorder;
+	}
+
+	public void setAn_recorder(String an_recorder) {
+		this.an_recorder = an_recorder;
+	}
+
+	public String getAn_remark() {
+		return an_remark;
+	}
+
+	public void setAn_remark(String an_remark) {
+		this.an_remark = an_remark;
+	}
+
+	public Date getAn_date() {
+		return an_date;
+	}
+
+	public void setAn_date(Date an_date) {
+		this.an_date = an_date;
+	}
+
+	public List<AcceptNotifyDetailPO> getDetails() {
+		return details;
+	}
+
+	public void setDetails(List<AcceptNotifyDetailPO> details) {
+		this.details = details;
+	}
+
+	public AcceptNotify map() {
+		AcceptNotify.Builder builder = AcceptNotify.newBuilder();
+		if (!NumberUtils.isEmpty(b2b_ss_id)) {
+			builder.setB2BSsId(b2b_ss_id);
+		}
+		builder.setAnVenduu(an_venduu);
+		if (!StringUtils.isEmpty(an_currency)) {
+			builder.setAnCurrency(an_currency);
+		}
+		if (null != an_rate) {
+			builder.setAnRate(an_rate);
+		}
+		if (!StringUtils.isEmpty(an_payment)) {
+			builder.setAnPayment(an_payment);
+		}
+		if (!NumberUtils.isEmpty(an_buyeruu)) {
+			builder.setAnBuyeruu(an_buyeruu);
+		}
+		if (!StringUtils.isEmpty(an_remark)) {
+			builder.setAnRemark(an_remark);
+		}
+		if (!StringUtils.isEmpty(an_sendcode)) {
+			builder.setAnSendcode(an_sendcode);
+		}
+		if (!StringUtils.isEmpty(an_recorder)) {
+			builder.setAnRecorder(an_recorder);
+		}
+		if (null != an_date) {
+			builder.setAnDate(an_date.getTime());
+		}
+		builder.setAnId(an_id);
+		if (!CollectionUtils.isEmpty(details)) {
+			details.forEach(detail -> builder.addDetailList(detail.map()));
+		}
+		return builder.build();
+	}
+
+	@Override
+	public Object id() {
+		return an_id;
+	}
+}

+ 115 - 0
uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/po/AcceptNotifyVerifyPO.java

@@ -0,0 +1,115 @@
+package com.usoftchina.uas.pl.b2b.po;
+
+import com.usoft.b2b.external.erp.deliver.api.entity.AcceptNotifyVerify;
+import com.usoftchina.uas.pl.entity.KeyEntity;
+import com.usoftchina.uas.pl.utils.NumberUtils;
+import com.usoftchina.uas.pl.utils.StringUtils;
+
+import java.util.Date;
+
+/**
+ * 已检验的收料单
+ * @author suntg
+ */
+public class AcceptNotifyVerifyPO implements KeyEntity {
+
+	private Long vad_id;
+	private Long b2b_ss_id;
+	private short and_detno;
+	private Double vad_jyqty;
+	private String ve_code;
+	private Double ve_okqty;
+	private Double ve_notokqty;
+	private String ve_testman;
+	private Date ve_date;
+	
+	public Long getB2b_ss_id() {
+		return b2b_ss_id;
+	}
+	public void setB2b_ss_id(Long b2b_ss_id) {
+		this.b2b_ss_id = b2b_ss_id;
+	}
+	public short getAnd_detno() {
+		return and_detno;
+	}
+	public void setAnd_detno(short and_detno) {
+		this.and_detno = and_detno;
+	}
+	public Long getVad_id() {
+		return vad_id;
+	}
+	public void setVad_id(Long vad_id) {
+		this.vad_id = vad_id;
+	}
+	public Double getVad_jyqty() {
+		return vad_jyqty;
+	}
+	public void setVad_jyqty(Double vad_jyqty) {
+		this.vad_jyqty = vad_jyqty;
+	}
+	public String getVe_code() {
+		return ve_code;
+	}
+	public void setVe_code(String ve_code) {
+		this.ve_code = ve_code;
+	}
+	public Double getVe_okqty() {
+		return ve_okqty;
+	}
+	public void setVe_okqty(Double ve_okqty) {
+		this.ve_okqty = ve_okqty;
+	}
+	public Double getVe_notokqty() {
+		return ve_notokqty;
+	}
+	public void setVe_notokqty(Double ve_notokqty) {
+		this.ve_notokqty = ve_notokqty;
+	}
+	public String getVe_testman() {
+		return ve_testman;
+	}
+	public void setVe_testman(String ve_testman) {
+		this.ve_testman = ve_testman;
+	}
+	public Date getVe_date() {
+		return ve_date;
+	}
+	public void setVe_date(Date ve_date) {
+		this.ve_date = ve_date;
+	}
+
+	public AcceptNotifyVerify map() {
+		AcceptNotifyVerify.Builder builder = AcceptNotifyVerify.newBuilder();
+		if (!NumberUtils.isEmpty(vad_id)) {
+			builder.setVadId(vad_id);
+		}
+		if (!NumberUtils.isEmpty(b2b_ss_id)) {
+			builder.setB2BSsId(b2b_ss_id);
+		}
+		builder.setAndDetno(and_detno);
+		if (null != vad_jyqty) {
+			builder.setVadJyqty(vad_jyqty);
+		}
+		if (!StringUtils.isEmpty(ve_code)) {
+			builder.setVeCode(ve_code);
+		}
+		if (null != ve_okqty) {
+			builder.setVeOkqty(ve_okqty);
+		}
+		if (null != ve_notokqty) {
+			builder.setVeNotokqty(ve_notokqty);
+		}
+		if (!StringUtils.isEmpty(ve_testman)) {
+			builder.setVeTestman(ve_testman);
+		}
+		if (null != ve_date) {
+			builder.setVeDate(ve_date.getTime());
+		}
+		return builder.build();
+	}
+
+	@Override
+	public Object id() {
+		return vad_id;
+	}
+}

+ 88 - 0
uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/po/AttachPO.java

@@ -0,0 +1,88 @@
+package com.usoftchina.uas.pl.b2b.po;
+
+import com.usoft.b2b.external.erp.order.api.entity.Purchase;
+import com.usoftchina.uas.pl.utils.NumberUtils;
+import com.usoftchina.uas.pl.utils.StringUtils;
+
+import java.io.Serializable;
+
+/**
+ * 附件信息
+ * 
+ * @author suntg
+ * 
+ */
+public class AttachPO implements Serializable {
+
+	public static final String DOWN_FILE_ACTION = "/common/downloadbyId.action?id=";
+
+	/**
+	 * Default serialVersionUID
+	 */
+	private static final long serialVersionUID = 1L;
+	/**
+	 * ID
+	 */
+	private Long fp_id;
+	/**
+	 * 附件名称
+	 */
+	private String fp_name;
+	/**
+	 * 附件Url
+	 */
+	private String fp_url;
+	/**
+	 * 附件大小
+	 */
+	private Long fp_size;
+
+	public Long getFp_id() {
+		return fp_id;
+	}
+
+	public void setFp_id(Long fp_id) {
+		this.fp_id = fp_id;
+	}
+
+	public String getFp_name() {
+		return fp_name;
+	}
+
+	public void setFp_name(String fp_name) {
+		this.fp_name = fp_name;
+	}
+
+	public String getFp_url() {
+		return fp_url;
+	}
+
+	public void setFp_url(String fp_url) {
+		this.fp_url = fp_url;
+	}
+
+	public Long getFp_size() {
+		return fp_size;
+	}
+
+	public void setFp_size(Long fp_size) {
+		this.fp_size = fp_size;
+	}
+
+	public Purchase.PurchaseDetail.Attach map() {
+		Purchase.PurchaseDetail.Attach.Builder builder = Purchase.PurchaseDetail.Attach.newBuilder();
+		if (!NumberUtils.isEmpty(fp_id)) {
+			builder.setFpId(fp_id);
+		}
+		if (!StringUtils.isEmpty(fp_name)) {
+			builder.setFpName(fp_name);
+		}
+		if (!StringUtils.isEmpty(fp_url)) {
+			builder.setFpUrl(fp_url);
+		}
+		if (null != fp_size) {
+			builder.setFpSize(fp_size);
+		}
+		return builder.build();
+	}
+}

+ 196 - 0
uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/po/PurchaseBillDetailPO.java

@@ -0,0 +1,196 @@
+package com.usoftchina.uas.pl.b2b.po;
+
+import com.usoft.b2b.external.erp.invoice.api.entity.APBillDetail;
+import com.usoftchina.uas.pl.utils.StringUtils;
+
+/**
+ * 采购方角度ERP APBill明细
+ * @author suntg
+ * @date 201541710:32:24
+ */
+public class PurchaseBillDetailPO {
+
+	private Short abd_detno;
+	private String abd_ordercode;
+	private Short abd_orderdetno;
+	private String abd_pdinoutno;
+	private String abd_prodcode;
+	private Double abd_thisvoqty;
+	private Double abd_price;
+	private Double abd_taxrate;
+	private Double abd_amount;
+	private Double abd_totalbillprice;
+	private Double abd_qty;
+	private Double abd_thisvoprice;
+	private Double abd_apamount;
+	private Double abd_noapamount;
+	private Double abd_taxamount;
+	private String abd_remark;
+	private Double abd_invoqty;
+	private Double abd_yqty;
+
+	public Short getAbd_detno() {
+		return abd_detno;
+	}
+	public void setAbd_detno(Short abd_detno) {
+		this.abd_detno = abd_detno;
+	}
+	public String getAbd_ordercode() {
+		return abd_ordercode;
+	}
+	public void setAbd_ordercode(String abd_ordercode) {
+		this.abd_ordercode = abd_ordercode;
+	}
+	public Short getAbd_orderdetno() {
+		return abd_orderdetno;
+	}
+	public void setAbd_orderdetno(Short abd_orderdetno) {
+		this.abd_orderdetno = abd_orderdetno;
+	}
+	public String getAbd_pdinoutno() {
+		return abd_pdinoutno;
+	}
+	public void setAbd_pdinoutno(String abd_pdinoutno) {
+		this.abd_pdinoutno = abd_pdinoutno;
+	}
+	public String getAbd_prodcode() {
+		return abd_prodcode;
+	}
+	public void setAbd_prodcode(String abd_prodcode) {
+		this.abd_prodcode = abd_prodcode;
+	}
+	public Double getAbd_thisvoqty() {
+		return abd_thisvoqty;
+	}
+	public void setAbd_thisvoqty(Double abd_thisvoqty) {
+		this.abd_thisvoqty = abd_thisvoqty;
+	}
+	public Double getAbd_price() {
+		return abd_price;
+	}
+	public void setAbd_price(Double abd_price) {
+		this.abd_price = abd_price;
+	}
+	public Double getAbd_taxrate() {
+		return abd_taxrate;
+	}
+	public void setAbd_taxrate(Double abd_taxrate) {
+		this.abd_taxrate = abd_taxrate;
+	}
+	public Double getAbd_amount() {
+		return abd_amount;
+	}
+	public void setAbd_amount(Double abd_amount) {
+		this.abd_amount = abd_amount;
+	}
+	public Double getAbd_totalbillprice() {
+		return abd_totalbillprice;
+	}
+	public void setAbd_totalbillprice(Double abd_totalbillprice) {
+		this.abd_totalbillprice = abd_totalbillprice;
+	}
+	public Double getAbd_qty() {
+		return abd_qty;
+	}
+	public void setAbd_qty(Double abd_qty) {
+		this.abd_qty = abd_qty;
+	}
+	public Double getAbd_thisvoprice() {
+		return abd_thisvoprice;
+	}
+	public void setAbd_thisvoprice(Double abd_thisvoprice) {
+		this.abd_thisvoprice = abd_thisvoprice;
+	}
+	public Double getAbd_apamount() {
+		return abd_apamount;
+	}
+	public void setAbd_apamount(Double abd_apamount) {
+		this.abd_apamount = abd_apamount;
+	}
+	public Double getAbd_noapamount() {
+		return abd_noapamount;
+	}
+	public void setAbd_noapamount(Double abd_noapamount) {
+		this.abd_noapamount = abd_noapamount;
+	}
+	public Double getAbd_taxamount() {
+		return abd_taxamount;
+	}
+	public void setAbd_taxamount(Double abd_taxamount) {
+		this.abd_taxamount = abd_taxamount;
+	}
+	public String getAbd_remark() {
+		return abd_remark;
+	}
+	public void setAbd_remark(String abd_remark) {
+		this.abd_remark = abd_remark;
+	}
+	public Double getAbd_invoqty() {
+		return abd_invoqty;
+	}
+	public void setAbd_invoqty(Double abd_invoqty) {
+		this.abd_invoqty = abd_invoqty;
+	}
+	public Double getAbd_yqty() {
+		return abd_yqty;
+	}
+	public void setAbd_yqty(Double abd_yqty) {
+		this.abd_yqty = abd_yqty;
+	}
+
+	public APBillDetail map() {
+		APBillDetail.Builder builder = APBillDetail.newBuilder();
+		if (null != abd_detno) {
+			builder.setAbdDetno(abd_detno);
+		}
+		if (!StringUtils.isEmpty(abd_ordercode)) {
+			builder.setAbdOrdercode(abd_ordercode);
+		}
+		if (null != abd_orderdetno) {
+			builder.setAbdOrderdetno(abd_orderdetno);
+		}
+		if (!StringUtils.isEmpty(abd_pdinoutno)) {
+			builder.setAbdPdinoutno(abd_pdinoutno);
+		}
+		if (!StringUtils.isEmpty(abd_prodcode)) {
+			builder.setAbdProdcode(abd_prodcode);
+		}
+		if (null != abd_thisvoqty) {
+			builder.setAbdThisvoqty(abd_thisvoqty);
+		}
+		if (null != abd_price) {
+			builder.setAbdPrice(abd_price);
+		}
+		if (null != abd_taxrate) {
+			builder.setAbdTaxrate(abd_taxrate);
+		}
+		if (null != abd_amount) {
+			builder.setAbdAmount(abd_amount);
+		}
+		if (null != abd_totalbillprice) {
+			builder.setAbdTotalbillprice(abd_totalbillprice);
+		}
+		if (null != abd_qty) {
+			builder.setAbdQty(abd_qty);
+		}
+		if (null != abd_thisvoprice) {
+			builder.setAbdThisvoprice(abd_thisvoprice);
+		}
+		if (null != abd_apamount) {
+			builder.setAbdApamount(abd_apamount);
+		}
+		if (null != abd_noapamount) {
+			builder.setAbdNoapamount(abd_noapamount);
+		}
+		if (!StringUtils.isEmpty(abd_remark)) {
+			builder.setAbdRemark(abd_remark);
+		}
+		if (null != abd_invoqty) {
+			builder.setAbdInvoqty(abd_invoqty);
+		}
+		if (null != abd_yqty) {
+			builder.setAbdYqty(abd_yqty);
+		}
+		return builder.build();
+	}
+}

+ 306 - 0
uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/po/PurchaseBillPO.java

@@ -0,0 +1,306 @@
+package com.usoftchina.uas.pl.b2b.po;
+
+import com.usoft.b2b.external.erp.invoice.api.entity.APBill;
+import com.usoftchina.uas.pl.entity.KeyEntity;
+import com.usoftchina.uas.pl.utils.CollectionUtils;
+import com.usoftchina.uas.pl.utils.NumberUtils;
+import com.usoftchina.uas.pl.utils.StringUtils;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 采购方角度ERP应付票据单
+ *
+ * @author suntg
+ * @date 201541710:32:24
+ */
+public class PurchaseBillPO implements KeyEntity {
+
+    private Long ab_id;
+    private String ab_code;
+    private Date ab_date;
+    private Long ab_yearmonth;
+    private String ab_currency;
+    private Double ab_rate;
+    private String ab_buyer;
+    private Long ab_vendoruu;
+    private String ab_status;
+    private String ab_payments;
+    private Date ab_paydate;
+    private String ab_refno;
+    private String ab_recorder;
+    private Date ab_indate;
+    private Double ab_apamount;
+    private Double ab_payamount;
+    private String ab_pricetermdes;
+    private Double ab_taxsum;
+    private Double ab_differ;
+    private String ab_remark;
+    private List<PurchaseBillDetailPO> details;
+    private Long ab_b2bid;
+    private Long ab_customeruu;
+
+    public Long getAb_id() {
+        return ab_id;
+    }
+
+    public void setAb_id(Long ab_id) {
+        this.ab_id = ab_id;
+    }
+
+    public String getAb_code() {
+        return ab_code;
+    }
+
+    public void setAb_code(String ab_code) {
+        this.ab_code = ab_code;
+    }
+
+    public Date getAb_date() {
+        return ab_date;
+    }
+
+    public void setAb_date(Date ab_date) {
+        this.ab_date = ab_date;
+    }
+
+    public Long getAb_yearmonth() {
+        return ab_yearmonth;
+    }
+
+    public void setAb_yearmonth(Long ab_yearmonth) {
+        this.ab_yearmonth = ab_yearmonth;
+    }
+
+    public String getAb_currency() {
+        return ab_currency;
+    }
+
+    public void setAb_currency(String ab_currency) {
+        this.ab_currency = ab_currency;
+    }
+
+    public Double getAb_rate() {
+        return ab_rate;
+    }
+
+    public void setAb_rate(Double ab_rate) {
+        this.ab_rate = ab_rate;
+    }
+
+    public String getAb_buyer() {
+        return ab_buyer;
+    }
+
+    public void setAb_buyer(String ab_buyer) {
+        this.ab_buyer = ab_buyer;
+    }
+
+    public Long getAb_vendoruu() {
+        return ab_vendoruu;
+    }
+
+    public void setAb_vendoruu(Long ab_vendoruu) {
+        this.ab_vendoruu = ab_vendoruu;
+    }
+
+    public String getAb_status() {
+        return ab_status;
+    }
+
+    public void setAb_status(String ab_status) {
+        this.ab_status = ab_status;
+    }
+
+    public String getAb_payments() {
+        return ab_payments;
+    }
+
+    public void setAb_payments(String ab_payments) {
+        this.ab_payments = ab_payments;
+    }
+
+    public Date getAb_paydate() {
+        return ab_paydate;
+    }
+
+    public void setAb_paydate(Date ab_paydate) {
+        this.ab_paydate = ab_paydate;
+    }
+
+    public String getAb_refno() {
+        return ab_refno;
+    }
+
+    public void setAb_refno(String ab_refno) {
+        this.ab_refno = ab_refno;
+    }
+
+    public String getAb_recorder() {
+        return ab_recorder;
+    }
+
+    public void setAb_recorder(String ab_recorder) {
+        this.ab_recorder = ab_recorder;
+    }
+
+    public Date getAb_indate() {
+        return ab_indate;
+    }
+
+    public void setAb_indate(Date ab_indate) {
+        this.ab_indate = ab_indate;
+    }
+
+    public Double getAb_apamount() {
+        return ab_apamount;
+    }
+
+    public void setAb_apamount(Double ab_apamount) {
+        this.ab_apamount = ab_apamount;
+    }
+
+    public Double getAb_payamount() {
+        return ab_payamount;
+    }
+
+    public void setAb_payamount(Double ab_payamount) {
+        this.ab_payamount = ab_payamount;
+    }
+
+    public String getAb_pricetermdes() {
+        return ab_pricetermdes;
+    }
+
+    public void setAb_pricetermdes(String ab_pricetermdes) {
+        this.ab_pricetermdes = ab_pricetermdes;
+    }
+
+    public Double getAb_taxsum() {
+        return ab_taxsum;
+    }
+
+    public void setAb_taxsum(Double ab_taxsum) {
+        this.ab_taxsum = ab_taxsum;
+    }
+
+    public Double getAb_differ() {
+        return ab_differ;
+    }
+
+    public void setAb_differ(Double ab_differ) {
+        this.ab_differ = ab_differ;
+    }
+
+    public String getAb_remark() {
+        return ab_remark;
+    }
+
+    public void setAb_remark(String ab_remark) {
+        this.ab_remark = ab_remark;
+    }
+
+    public List<PurchaseBillDetailPO> getDetails() {
+        return details;
+    }
+
+    public void setDetails(List<PurchaseBillDetailPO> details) {
+        this.details = details;
+    }
+
+    public Long getAb_b2bid() {
+        return ab_b2bid;
+    }
+
+    public void setAb_b2bid(Long ab_b2bid) {
+        this.ab_b2bid = ab_b2bid;
+    }
+
+    public Long getAb_customeruu() {
+        return ab_customeruu;
+    }
+
+    public void setAb_customeruu(Long ab_customeruu) {
+        this.ab_customeruu = ab_customeruu;
+    }
+
+    public APBill map() {
+        APBill.Builder builder = APBill.newBuilder();
+        if (null != ab_id) {
+            builder.setAbId(ab_id);
+        }
+        if (!StringUtils.isEmpty(ab_code)) {
+            builder.setAbCode(ab_code);
+        }
+        if (null != ab_date) {
+            builder.setAbDate(ab_date.getTime());
+        }
+        if (null != ab_yearmonth) {
+            builder.setAbYearmonth(ab_yearmonth);
+        }
+        if (!StringUtils.isEmpty(ab_currency)) {
+            builder.setAbCurrency(ab_currency);
+        }
+        if (null != ab_rate) {
+            builder.setAbRate(ab_rate);
+        }
+        if (!StringUtils.isEmpty(ab_buyer)) {
+            builder.setAbBuyer(ab_buyer);
+        }
+        if (!NumberUtils.isEmpty(ab_vendoruu)) {
+            builder.setAbVendoruu(ab_vendoruu);
+        }
+        if (!StringUtils.isEmpty(ab_status)) {
+            builder.setAbStatus(ab_status);
+        }
+        if (!StringUtils.isEmpty(ab_payments)) {
+            builder.setAbPayments(ab_payments);
+        }
+        if (null != ab_paydate) {
+            builder.setAbPaydate(ab_paydate.getTime());
+        }
+        if (!StringUtils.isEmpty(ab_refno)) {
+            builder.setAbRefno(ab_refno);
+        }
+        if (!StringUtils.isEmpty(ab_recorder)) {
+            builder.setAbRecorder(ab_recorder);
+        }
+        if (null != ab_indate) {
+            builder.setAbIndate(ab_indate.getTime());
+        }
+        if (null != ab_apamount) {
+            builder.setAbApamount(ab_apamount);
+        }
+        if (null != ab_payamount) {
+            builder.setAbPayamount(ab_payamount);
+        }
+        if (!StringUtils.isEmpty(ab_pricetermdes)) {
+            builder.setAbPricetermdes(ab_pricetermdes);
+        }
+        if (null != ab_taxsum) {
+            builder.setAbTaxsum(ab_taxsum);
+        }
+        if (null != ab_differ) {
+            builder.setAbDiffer(ab_differ);
+        }
+        if (!StringUtils.isEmpty(ab_remark)) {
+            builder.setAbRemark(ab_remark);
+        }
+        if (!NumberUtils.isEmpty(ab_b2bid)) {
+            builder.setAbB2Bid(ab_b2bid);
+        }
+        if (!NumberUtils.isEmpty(ab_customeruu)) {
+            builder.setAbCustomeruu(ab_customeruu);
+        }
+        if (!CollectionUtils.isEmpty(details)) {
+            details.forEach(detail -> builder.addDetails(detail.map()));
+        }
+        return builder.build();
+    }
+
+    @Override
+    public Object id() {
+        return ab_id;
+    }
+}

+ 164 - 0
uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/po/PurchaseChangeDetailPO.java

@@ -0,0 +1,164 @@
+package com.usoftchina.uas.pl.b2b.po;
+
+import com.usoft.b2b.external.erp.order.api.entity.PurchaseChange;
+import com.usoftchina.uas.pl.utils.StringUtils;
+
+import java.util.Date;
+
+public class PurchaseChangeDetailPO {
+
+	private Long pcd_pcid;
+	private short pcd_detno;
+	private short pcd_pddetno;
+	private String pcd_prodcode;
+	private String pcd_newprodcode;
+	private Double pcd_oldqty;
+	private Double pcd_newqty;
+	private Double pcd_oldprice;
+	private Double pcd_newprice;
+	private Date pcd_olddelivery;
+	private Date pcd_newdelivery;
+	private Float pcd_taxrate;
+	private Float pcd_newtaxrate;
+	private String pcd_remark;
+
+	public Long getPcd_pcid() {
+		return pcd_pcid;
+	}
+
+	public void setPcd_pcid(Long pcd_pcid) {
+		this.pcd_pcid = pcd_pcid;
+	}
+
+	public short getPcd_detno() {
+		return pcd_detno;
+	}
+
+	public void setPcd_detno(short pcd_detno) {
+		this.pcd_detno = pcd_detno;
+	}
+
+	public short getPcd_pddetno() {
+		return pcd_pddetno;
+	}
+
+	public void setPcd_pddetno(short pcd_pddetno) {
+		this.pcd_pddetno = pcd_pddetno;
+	}
+
+	public String getPcd_prodcode() {
+		return pcd_prodcode;
+	}
+
+	public void setPcd_prodcode(String pcd_prodcode) {
+		this.pcd_prodcode = pcd_prodcode;
+	}
+
+	public String getPcd_newprodcode() {
+		return pcd_newprodcode;
+	}
+
+	public void setPcd_newprodcode(String pcd_newprodcode) {
+		this.pcd_newprodcode = pcd_newprodcode;
+	}
+
+	public Double getPcd_oldqty() {
+		return pcd_oldqty;
+	}
+
+	public void setPcd_oldqty(Double pcd_oldqty) {
+		this.pcd_oldqty = pcd_oldqty;
+	}
+
+	public Double getPcd_newqty() {
+		return pcd_newqty;
+	}
+
+	public void setPcd_newqty(Double pcd_newqty) {
+		this.pcd_newqty = pcd_newqty;
+	}
+
+	public Double getPcd_oldprice() {
+		return pcd_oldprice;
+	}
+
+	public void setPcd_oldprice(Double pcd_oldprice) {
+		this.pcd_oldprice = pcd_oldprice;
+	}
+
+	public Double getPcd_newprice() {
+		return pcd_newprice;
+	}
+
+	public void setPcd_newprice(Double pcd_newprice) {
+		this.pcd_newprice = pcd_newprice;
+	}
+
+	public Date getPcd_olddelivery() {
+		return pcd_olddelivery;
+	}
+
+	public void setPcd_olddelivery(Date pcd_olddelivery) {
+		this.pcd_olddelivery = pcd_olddelivery;
+	}
+
+	public Date getPcd_newdelivery() {
+		return pcd_newdelivery;
+	}
+
+	public void setPcd_newdelivery(Date pcd_newdelivery) {
+		this.pcd_newdelivery = pcd_newdelivery;
+	}
+
+	public Float getPcd_taxrate() {
+		return pcd_taxrate;
+	}
+
+	public void setPcd_taxrate(Float pcd_taxrate) {
+		this.pcd_taxrate = pcd_taxrate;
+	}
+
+	public Float getPcd_newtaxrate() {
+		return pcd_newtaxrate;
+	}
+
+	public void setPcd_newtaxrate(Float pcd_newtaxrate) {
+		this.pcd_newtaxrate = pcd_newtaxrate;
+	}
+
+	public String getPcd_remark() {
+		return pcd_remark;
+	}
+
+	public void setPcd_remark(String pcd_remark) {
+		this.pcd_remark = pcd_remark;
+	}
+
+	public PurchaseChange.PurchaseChangeDetail map() {
+		PurchaseChange.PurchaseChangeDetail.Builder builder = PurchaseChange.PurchaseChangeDetail.newBuilder();
+		builder.setPcdDetno(pcd_detno);
+		builder.setPcdPddetno(pcd_pddetno);
+		if (!StringUtils.isEmpty(pcd_prodcode)) {
+			builder.setPcdProdcode(pcd_prodcode);
+		}
+		if (!StringUtils.isEmpty(pcd_newprodcode)) {
+			builder.setPcdNewprodcode(pcd_newprodcode);
+		}
+		if (null != pcd_newqty) {
+			builder.setPcdNewqty(pcd_newqty);
+		}
+		if (null != pcd_newprice) {
+			builder.setPcdNewprice(pcd_newprice);
+		}
+		if (null != pcd_newdelivery) {
+			builder.setPcdNewdelivery(pcd_newdelivery.getTime());
+		}
+		if (null != pcd_newtaxrate) {
+			builder.setPcdNewtaxrate(pcd_newtaxrate);
+		}
+		if (!StringUtils.isEmpty(pcd_remark)) {
+			builder.setPcdRemark(pcd_remark);
+		}
+		return builder.build();
+	}
+}

+ 256 - 0
uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/po/PurchaseChangePO.java

@@ -0,0 +1,256 @@
+package com.usoftchina.uas.pl.b2b.po;
+
+import com.usoft.b2b.external.erp.order.api.entity.PurchaseChange;
+import com.usoftchina.uas.pl.entity.KeyEntity;
+import org.springframework.util.CollectionUtils;
+import org.springframework.util.StringUtils;
+
+import java.util.Date;
+import java.util.List;
+
+public class PurchaseChangePO implements KeyEntity {
+
+	private Long pc_id;
+	private String pc_code;
+	private String pc_purccode;
+	private Date pc_indate;
+	private String pc_recorder;
+	private String pc_payments;
+	private String pc_newpayments;
+	private String pc_currency;
+	private String pc_newcurrency;
+	private Float pc_rate;
+	private Float pc_newrate;
+	private String pc_apvendname;
+	private String pc_newapvendname;
+	private String pc_apvendcode;
+	private String pc_newapvendcode;
+	private String pc_description;
+	private String pc_remark;
+	private Short pc_agreed;
+	private Short pc_needvendcheck;
+	private List<PurchaseChangeDetailPO> changeDetails;
+
+	public Long getPc_id() {
+		return pc_id;
+	}
+
+	public void setPc_id(Long pc_id) {
+		this.pc_id = pc_id;
+	}
+
+	public String getPc_code() {
+		return pc_code;
+	}
+
+	public void setPc_code(String pc_code) {
+		this.pc_code = pc_code;
+	}
+
+	public String getPc_purccode() {
+		return pc_purccode;
+	}
+
+	public void setPc_purccode(String pc_purccode) {
+		this.pc_purccode = pc_purccode;
+	}
+
+	public Date getPc_indate() {
+		return pc_indate;
+	}
+
+	public void setPc_indate(Date pc_indate) {
+		this.pc_indate = pc_indate;
+	}
+
+	public String getPc_recorder() {
+		return pc_recorder;
+	}
+
+	public void setPc_recorder(String pc_recorder) {
+		this.pc_recorder = pc_recorder;
+	}
+
+	public String getPc_payments() {
+		return pc_payments;
+	}
+
+	public void setPc_payments(String pc_payments) {
+		this.pc_payments = pc_payments;
+	}
+
+	public String getPc_newpayments() {
+		return pc_newpayments;
+	}
+
+	public void setPc_newpayments(String pc_newpayments) {
+		this.pc_newpayments = pc_newpayments;
+	}
+
+	public String getPc_currency() {
+		return pc_currency;
+	}
+
+	public void setPc_currency(String pc_currency) {
+		this.pc_currency = pc_currency;
+	}
+
+	public String getPc_newcurrency() {
+		return pc_newcurrency;
+	}
+
+	public void setPc_newcurrency(String pc_newcurrency) {
+		this.pc_newcurrency = pc_newcurrency;
+	}
+
+	public Float getPc_rate() {
+		return pc_rate;
+	}
+
+	public void setPc_rate(Float pc_rate) {
+		this.pc_rate = pc_rate;
+	}
+
+	public Float getPc_newrate() {
+		return pc_newrate;
+	}
+
+	public void setPc_newrate(Float pc_newrate) {
+		this.pc_newrate = pc_newrate;
+	}
+
+	public String getPc_description() {
+		return pc_description;
+	}
+
+	public void setPc_description(String pc_description) {
+		this.pc_description = pc_description;
+	}
+
+	public String getPc_remark() {
+		return pc_remark;
+	}
+
+	public void setPc_remark(String pc_remark) {
+		this.pc_remark = pc_remark;
+	}
+
+	public Short getPc_agreed() {
+		return pc_agreed;
+	}
+
+	public void setPc_agreed(Short pc_agreed) {
+		this.pc_agreed = pc_agreed;
+	}
+
+	public Short getPc_needvendcheck() {
+		return pc_needvendcheck;
+	}
+
+	public void setPc_needvendcheck(Short pc_needvendcheck) {
+		this.pc_needvendcheck = pc_needvendcheck;
+	}
+
+	public List<PurchaseChangeDetailPO> getChangeDetails() {
+		return changeDetails;
+	}
+
+	public void setChangeDetails(List<PurchaseChangeDetailPO> changeDetails) {
+		this.changeDetails = changeDetails;
+	}
+
+	public String getPc_apvendname() {
+		return pc_apvendname;
+	}
+
+	public void setPc_apvendname(String pc_apvendname) {
+		this.pc_apvendname = pc_apvendname;
+	}
+
+	public String getPc_newapvendname() {
+		return pc_newapvendname;
+	}
+
+	public void setPc_newapvendname(String pc_newapvendname) {
+		this.pc_newapvendname = pc_newapvendname;
+	}
+
+	public String getPc_apvendcode() {
+		return pc_apvendcode;
+	}
+
+	public void setPc_apvendcode(String pc_apvendcode) {
+		this.pc_apvendcode = pc_apvendcode;
+	}
+
+	public String getPc_newapvendcode() {
+		return pc_newapvendcode;
+	}
+
+	public void setPc_newapvendcode(String pc_newapvendcode) {
+		this.pc_newapvendcode = pc_newapvendcode;
+	}
+
+	public PurchaseChange map() {
+		PurchaseChange.Builder builder = PurchaseChange.newBuilder();
+		if (null != pc_id) {
+			builder.setPcId(pc_id);
+		}
+		if (!StringUtils.isEmpty(pc_code)) {
+			builder.setPcCode(pc_code);
+		}
+		if (!StringUtils.isEmpty(pc_purccode)) {
+			builder.setPcPurccode(pc_purccode);
+		}
+		if (null != pc_indate) {
+			builder.setPcIndate(pc_indate.getTime());
+		}
+		if (!StringUtils.isEmpty(pc_recorder)) {
+			builder.setPcRecorder(pc_recorder);
+		}
+		if (!StringUtils.isEmpty(pc_newpayments)) {
+			builder.setPcNewpayments(pc_newpayments);
+		}
+		if (!StringUtils.isEmpty(pc_newcurrency)) {
+			builder.setPcNewcurrency(pc_newcurrency);
+		}
+		if (null != pc_newrate) {
+			builder.setPcNewrate(pc_newrate);
+		}
+		if (!StringUtils.isEmpty(pc_apvendname)) {
+			builder.setPcApvendname(pc_apvendname);
+		}
+		if (!StringUtils.isEmpty(pc_newapvendname)) {
+			builder.setPcNewapvendname(pc_newapvendname);
+		}
+		if (!StringUtils.isEmpty(pc_apvendcode)) {
+			builder.setPcApvendcode(pc_apvendcode);
+		}
+		if (!StringUtils.isEmpty(pc_newapvendcode)) {
+			builder.setPcNewapvendcode(pc_newapvendcode);
+		}
+		if (!StringUtils.isEmpty(pc_description)) {
+			builder.setPcDescription(pc_description);
+		}
+		if (!StringUtils.isEmpty(pc_remark)) {
+			builder.setPcRemark(pc_remark);
+		}
+		if (null != pc_agreed) {
+			builder.setPcAgreed(pc_agreed);
+		}
+		if (null != pc_needvendcheck) {
+			builder.setPcNeedvendcheck(pc_needvendcheck);
+		}
+		if (!CollectionUtils.isEmpty(changeDetails)) {
+			changeDetails.forEach(detail -> {
+				builder.addChangeDetails(detail.map());
+			});
+		}
+		return builder.build();
+	}
+
+	@Override
+	public Object id() {
+		return pc_id;
+	}
+}

+ 63 - 0
uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/po/PurchaseDetailEndPO.java

@@ -0,0 +1,63 @@
+package com.usoftchina.uas.pl.b2b.po;
+
+import com.usoft.b2b.external.erp.order.api.entity.PurchaseDetailEnd;
+import com.usoftchina.uas.pl.entity.KeyEntity;
+
+/**
+ * ERP系统的采购订单明细(针对结案、反结案)
+ * 
+ * @author yingp
+ * 
+ */
+public class PurchaseDetailEndPO implements KeyEntity {
+
+	private String pd_code;
+	private short pd_detno;
+	private short pd_ended;
+	private Integer pd_id;
+
+	public String getPd_code() {
+		return pd_code;
+	}
+
+	public void setPd_code(String pd_code) {
+		this.pd_code = pd_code;
+	}
+
+	public short getPd_detno() {
+		return pd_detno;
+	}
+
+	public void setPd_detno(short pd_detno) {
+		this.pd_detno = pd_detno;
+	}
+
+	public short getPd_ended() {
+		return pd_ended;
+	}
+
+	public void setPd_ended(short pd_ended) {
+		this.pd_ended = pd_ended;
+	}
+
+	public Integer getPd_id() {
+		return pd_id;
+	}
+
+	public void setPd_id(Integer pd_id) {
+		this.pd_id = pd_id;
+	}
+
+	public PurchaseDetailEnd map() {
+		PurchaseDetailEnd.Builder builder = PurchaseDetailEnd.newBuilder();
+		builder.setPdCode(pd_code);
+		builder.setPdDetno(pd_detno);
+		builder.setPdEnded(pd_ended);
+		return builder.build();
+	}
+
+	@Override
+	public Object id() {
+		return pd_id;
+	}
+}

+ 464 - 0
uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/po/PurchaseDetailPO.java

@@ -0,0 +1,464 @@
+package com.usoftchina.uas.pl.b2b.po;
+
+import com.usoft.b2b.external.erp.order.api.entity.Purchase;
+import com.usoftchina.uas.pl.utils.NumberUtils;
+import com.usoftchina.uas.pl.utils.StringUtils;
+import org.springframework.util.CollectionUtils;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * ERP系统的采购订单明细
+ * 
+ * @author yingp
+ * 
+ */
+public class PurchaseDetailPO {
+
+	private String pd_code;
+	private String pd_prodcode;
+	private Double pd_qty;
+	private Double pd_price;
+	private Date pd_delivery;
+	private String pd_remark;
+	private Float pd_rate;
+	private short pd_detno;
+	private String pd_factory;
+	private String pd_vendspec;
+	private Integer pd_beipin;
+	private String pd_prattach;
+	//终端供应商名称
+	private String pd_purcvendname;
+	//终端供应商uu
+	private Long pd_purcvenduu;
+	//客户采购订单号
+	private String pd_custpurchasecode;
+	//客户采购订单序号
+	private Short pd_custpurchasedetno;
+	//收货客户
+	private String pd_acceptcustname;
+	//收货地址
+	private String pd_acceptcustaddress;
+	//收货客户uu
+	private Long pd_acceptcustuu;
+	//是否能发货
+	private String pd_hasissued;
+	//终端价格
+	private Float pd_purcprice;
+	//终端税率
+	private Float pd_purctaxrate;
+	//终端币别
+	private String pd_purccurrency;
+	//税收分类编码
+    private String pd_taxcode;
+    //开票名称
+    private String pd_billname;
+    //开票型号
+    private String pd_orispeccode;
+	private List<AttachPO> attaches;
+
+	//替代料号
+	private String pd_repprodcode;
+	//替代料名称
+	private String pd_repdetail;
+	//替代料规格
+	private String pd_repspec;
+
+	//旧料编号
+	private String pr_oldcode;
+	//旧料名称
+	private String pr_oldname;
+	//旧料规格
+	private String pr_oldspec;
+
+	//物料承认状态
+	private String pd_prmaterial;
+
+	// 顶层物料
+	private String pd_topmothercode;
+
+	public String getPd_topmothercode() {
+		return pd_topmothercode;
+	}
+
+	public void setPd_topmothercode(String pd_topmothercode) {
+		this.pd_topmothercode = pd_topmothercode;
+	}
+
+	public String getPd_prmaterial() {
+		return pd_prmaterial;
+	}
+
+	public void setPd_prmaterial(String pd_prmaterial) {
+		this.pd_prmaterial = pd_prmaterial;
+	}
+
+	public String getPr_oldcode() {
+		return pr_oldcode;
+	}
+
+	public void setPr_oldcode(String pr_oldcode) {
+		this.pr_oldcode = pr_oldcode;
+	}
+
+	public String getPr_oldname() {
+		return pr_oldname;
+	}
+
+	public void setPr_oldname(String pr_oldname) {
+		this.pr_oldname = pr_oldname;
+	}
+
+	public String getPr_oldspec() {
+		return pr_oldspec;
+	}
+
+	public void setPr_oldspec(String pr_oldspec) {
+		this.pr_oldspec = pr_oldspec;
+	}
+
+	public String getPd_repprodcode() {
+		return pd_repprodcode;
+	}
+
+	public void setPd_repprodcode(String pd_repprodcode) {
+		this.pd_repprodcode = pd_repprodcode;
+	}
+
+	public String getPd_repdetail() {
+		return pd_repdetail;
+	}
+
+	public void setPd_repdetail(String pd_repdetail) {
+		this.pd_repdetail = pd_repdetail;
+	}
+
+	public String getPd_repspec() {
+		return pd_repspec;
+	}
+
+	public void setPd_repspec(String pd_repspec) {
+		this.pd_repspec = pd_repspec;
+	}
+
+	public String getPd_taxcode() {
+		return pd_taxcode;
+	}
+
+	public void setPd_taxcode(String pd_taxcode) {
+		this.pd_taxcode = pd_taxcode;
+	}
+
+	public String getPd_billname() {
+		return pd_billname;
+	}
+
+	public void setPd_billname(String pd_billname) {
+		this.pd_billname = pd_billname;
+	}
+
+	public String getPd_orispeccode() {
+		return pd_orispeccode;
+	}
+
+	public void setPd_orispeccode(String pd_orispeccode) {
+		this.pd_orispeccode = pd_orispeccode;
+	}
+
+	public Float getPd_purcprice() {
+		return pd_purcprice;
+	}
+
+	public void setPd_purcprice(Float pd_purcprice) {
+		this.pd_purcprice = pd_purcprice;
+	}
+
+	public Float getPd_purctaxrate() {
+		return pd_purctaxrate;
+	}
+
+	public void setPd_purctaxrate(Float pd_purctaxrate) {
+		this.pd_purctaxrate = pd_purctaxrate;
+	}
+
+	public String getPd_purccurrency() {
+		return pd_purccurrency;
+	}
+
+	public void setPd_purccurrency(String pd_purccurrency) {
+		this.pd_purccurrency = pd_purccurrency;
+	}
+
+	public String getPd_vendspec() {
+		return pd_vendspec;
+	}
+
+	public void setPd_vendspec(String pd_vendspec) {
+		this.pd_vendspec = pd_vendspec;
+	}
+
+	public Long getPd_acceptcustuu() {
+		return pd_acceptcustuu;
+	}
+
+	public void setPd_acceptcustuu(Long pd_acceptcustuu) {
+		this.pd_acceptcustuu = pd_acceptcustuu;
+	}
+
+	public String getPd_hasissued() {
+		return pd_hasissued;
+	}
+
+	public void setPd_hasissued(String pd_hasissued) {
+		this.pd_hasissued = pd_hasissued;
+	}
+
+	public String getPd_factory() {
+		return pd_factory;
+	}
+
+	public void setPd_factory(String pd_factory) {
+		this.pd_factory = pd_factory;
+	}
+
+	public String getPd_code() {
+		return pd_code;
+	}
+
+	public void setPd_code(String pd_code) {
+		this.pd_code = pd_code;
+	}
+
+	public String getPd_prodcode() {
+		return pd_prodcode;
+	}
+
+	public void setPd_prodcode(String pd_prodcode) {
+		this.pd_prodcode = pd_prodcode;
+	}
+
+	public Double getPd_qty() {
+		return pd_qty;
+	}
+
+	public void setPd_qty(Double pd_qty) {
+		this.pd_qty = pd_qty;
+	}
+
+	public Double getPd_price() {
+		return pd_price;
+	}
+
+	public void setPd_price(Double pd_price) {
+		this.pd_price = pd_price;
+	}
+
+	public Date getPd_delivery() {
+		return pd_delivery;
+	}
+
+	public void setPd_delivery(Date pd_delivery) {
+		this.pd_delivery = pd_delivery;
+	}
+
+	public String getPd_remark() {
+		return pd_remark;
+	}
+
+	public void setPd_remark(String pd_remark) {
+		this.pd_remark = pd_remark;
+	}
+
+	public Float getPd_rate() {
+		return pd_rate;
+	}
+
+	public void setPd_rate(Float pd_rate) {
+		this.pd_rate = pd_rate;
+	}
+
+	public short getPd_detno() {
+		return pd_detno;
+	}
+
+	public void setPd_detno(short pd_detno) {
+		this.pd_detno = pd_detno;
+	}
+
+	public Integer getPd_beipin() {
+		return pd_beipin;
+	}
+
+	public void setPd_beipin(Integer pd_beipin) {
+		this.pd_beipin = pd_beipin;
+	}
+
+	public String getPd_prattach() {
+		return pd_prattach;
+	}
+
+	public void setPd_prattach(String pd_prattach) {
+		this.pd_prattach = pd_prattach;
+	}
+
+	public List<AttachPO> getAttaches() {
+		return attaches;
+	}
+
+	public void setAttaches(List<AttachPO> attaches) {
+		this.attaches = attaches;
+	}
+
+	public String getPd_purcvendname() {
+		return pd_purcvendname;
+	}
+
+	public void setPd_purcvendname(String pd_purcvendname) {
+		this.pd_purcvendname = pd_purcvendname;
+	}
+
+	public Long getPd_purcvenduu() {
+		return pd_purcvenduu;
+	}
+
+	public void setPd_purcvenduu(Long pd_purcvenduu) {
+		this.pd_purcvenduu = pd_purcvenduu;
+	}
+
+	public String getPd_custpurchasecode() {
+		return pd_custpurchasecode;
+	}
+
+	public void setPd_custpurchasecode(String pd_custpurchasecode) {
+		this.pd_custpurchasecode = pd_custpurchasecode;
+	}
+
+	public Short getPd_custpurchasedetno() {
+		return pd_custpurchasedetno;
+	}
+
+	public void setPd_custpurchasedetno(Short pd_custpurchasedetno) {
+		this.pd_custpurchasedetno = pd_custpurchasedetno;
+	}
+
+	public String getPd_acceptcustname() {
+		return pd_acceptcustname;
+	}
+
+	public void setPd_acceptcustname(String pd_acceptcustname) {
+		this.pd_acceptcustname = pd_acceptcustname;
+	}
+
+	public String getPd_acceptcustaddress() {
+		return pd_acceptcustaddress;
+	}
+
+	public void setPd_acceptcustaddress(String pd_acceptcustaddress) {
+		this.pd_acceptcustaddress = pd_acceptcustaddress;
+	}
+
+	public Purchase.PurchaseDetail map() {
+		Purchase.PurchaseDetail.Builder builder = Purchase.PurchaseDetail.newBuilder();
+		if (!StringUtils.isEmpty(pd_code)) {
+			builder.setPdCode(pd_code);
+		}
+		if (!StringUtils.isEmpty(pd_prodcode)) {
+			builder.setPdProdcode(pd_prodcode);
+		}
+		if (null != pd_qty) {
+			builder.setPdQty(pd_qty);
+		}
+		if (null != pd_price) {
+			builder.setPdPrice(pd_price);
+		}
+		if (null != pd_delivery) {
+			builder.setPdDelivery(pd_delivery.getTime());
+		}
+		if (!StringUtils.isEmpty(pd_remark)) {
+			builder.setPdRemark(pd_remark);
+		}
+		if (null != pd_rate) {
+			builder.setPdRate(pd_rate);
+		}
+		builder.setPdDetno(pd_detno);
+		if (!StringUtils.isEmpty(pd_factory)) {
+			builder.setPdFactory(pd_factory);
+		}
+		if (!StringUtils.isEmpty(pd_vendspec)) {
+			builder.setPdVendspec(pd_vendspec);
+		}
+		if (null != pd_beipin) {
+			builder.setPdBeipin(pd_beipin);
+		}
+		if (!StringUtils.isEmpty(pd_purcvendname)) {
+			builder.setPdPurcvendname(pd_purcvendname);
+		}
+		if (!NumberUtils.isEmpty(pd_purcvenduu)) {
+			builder.setPdPurcvenduu(pd_purcvenduu);
+		}
+		if (!StringUtils.isEmpty(pd_custpurchasecode)) {
+			builder.setPdCustpurchasecode(pd_custpurchasecode);
+		}
+		if (!NumberUtils.isEmpty(pd_custpurchasedetno)) {
+			builder.setPdCustpurchasedetno(pd_custpurchasedetno);
+		}
+		if (!StringUtils.isEmpty(pd_acceptcustname)) {
+			builder.setPdAcceptcustname(pd_acceptcustname);
+		}
+		if (!StringUtils.isEmpty(pd_acceptcustaddress)) {
+			builder.setPdAcceptcustaddress(pd_acceptcustaddress);
+		}
+		if (!NumberUtils.isEmpty(pd_acceptcustuu)) {
+			builder.setPdAcceptcustuu(pd_acceptcustuu);
+		}
+		if (!StringUtils.isEmpty(pd_hasissued)) {
+			builder.setPdHasissued(pd_hasissued);
+		}
+		if (null != pd_purcprice) {
+			builder.setPdPurcprice(pd_purcprice);
+		}
+		if (null != pd_purctaxrate) {
+			builder.setPdPurctaxrate(pd_purctaxrate);
+		}
+		if (!StringUtils.isEmpty(pd_purccurrency)) {
+			builder.setPdPurccurrency(pd_purccurrency);
+		}
+		if (!StringUtils.isEmpty(pd_taxcode)) {
+			builder.setPdTaxcode(pd_taxcode);
+		}
+		if (!StringUtils.isEmpty(pd_purccurrency)) {
+			builder.setPdPurccurrency(pd_purccurrency);
+		}
+		if (!StringUtils.isEmpty(pd_billname)) {
+			builder.setPdBillname(pd_billname);
+		}
+		if (!StringUtils.isEmpty(pd_orispeccode)) {
+			builder.setPdOrispeccode(pd_orispeccode);
+		}
+		if (!StringUtils.isEmpty(pd_repprodcode)) {
+			builder.setPdRepprodcode(pd_repprodcode);
+		}
+		if (!StringUtils.isEmpty(pd_repdetail)) {
+			builder.setPdRepdetail(pd_repdetail);
+		}
+		if (!StringUtils.isEmpty(pd_repspec)) {
+			builder.setPdRepspec(pd_repspec);
+		}
+		if (!StringUtils.isEmpty(pr_oldcode)) {
+			builder.setPrOldcode(pr_oldcode);
+		}
+		if (!StringUtils.isEmpty(pr_oldname)) {
+			builder.setPrOldname(pr_oldname);
+		}
+		if (!StringUtils.isEmpty(pr_oldspec)) {
+			builder.setPrOldspec(pr_oldspec);
+		}
+		if (!CollectionUtils.isEmpty(attaches)) {
+			attaches.forEach(attach -> {
+				builder.addAttaches(attach.map());
+			});
+		}
+		return builder.build();
+	}
+}

+ 181 - 0
uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/po/PurchaseNotifyPO.java

@@ -0,0 +1,181 @@
+package com.usoftchina.uas.pl.b2b.po;
+
+import com.usoft.b2b.external.erp.deliver.api.entity.PurchaseNotify;
+import com.usoftchina.uas.pl.entity.KeyEntity;
+import com.usoftchina.uas.pl.utils.NumberUtils;
+import com.usoftchina.uas.pl.utils.StringUtils;
+
+import java.util.Date;
+
+/**
+ * 买家ERP系统的送货提醒单(提醒卖家发货)
+ * 
+ * @author yingp
+ * 
+ */
+public class PurchaseNotifyPO implements KeyEntity {
+
+	private int pn_id;
+	private long ve_uu;
+	private Date pn_indate;
+	private Double pn_qty;
+	private Date pn_delivery;
+	private String pn_ordercode;
+	private Short pn_orderdetno;
+	private String pn_remark;
+	private Double pn_endqty;
+	// 物料最小包装数
+	private Double pr_zxbzs;
+	//b2bid
+	private Long pn_b2bid;
+	//终端供应商,为0表示正常送货提醒
+	private Long pn_terminalvenduu;
+
+	private Long pn_custb2bid;
+
+	public Long getPn_custb2bid() {
+		return pn_custb2bid;
+	}
+
+	public void setPn_custb2bid(Long pn_custb2bid) {
+		this.pn_custb2bid = pn_custb2bid;
+	}
+
+	public int getPn_id() {
+		return pn_id;
+	}
+
+	public void setPn_id(int pn_id) {
+		this.pn_id = pn_id;
+	}
+
+	public long getVe_uu() {
+		return ve_uu;
+	}
+
+	public void setVe_uu(long ve_uu) {
+		this.ve_uu = ve_uu;
+	}
+
+	public Date getPn_indate() {
+		return pn_indate;
+	}
+
+	public void setPn_indate(Date pn_indate) {
+		this.pn_indate = pn_indate;
+	}
+
+	public Double getPn_qty() {
+		return pn_qty;
+	}
+
+	public void setPn_qty(Double pn_qty) {
+		this.pn_qty = pn_qty;
+	}
+
+	public Date getPn_delivery() {
+		return pn_delivery;
+	}
+
+	public void setPn_delivery(Date pn_delivery) {
+		this.pn_delivery = pn_delivery;
+	}
+
+	public String getPn_ordercode() {
+		return pn_ordercode;
+	}
+
+	public void setPn_ordercode(String pn_ordercode) {
+		this.pn_ordercode = pn_ordercode;
+	}
+
+	public Short getPn_orderdetno() {
+		return pn_orderdetno;
+	}
+
+	public void setPn_orderdetno(Short pn_orderdetno) {
+		this.pn_orderdetno = pn_orderdetno;
+	}
+
+	public String getPn_remark() {
+		return pn_remark;
+	}
+
+	public void setPn_remark(String pn_remark) {
+		this.pn_remark = pn_remark;
+	}
+
+	public Double getPn_endqty() {
+		return pn_endqty;
+	}
+
+	public void setPn_endqty(Double pn_endqty) {
+		this.pn_endqty = pn_endqty;
+	}
+
+	public Double getPr_zxbzs() {
+		return pr_zxbzs;
+	}
+
+	public void setPr_zxbzs(Double pr_zxbzs) {
+		this.pr_zxbzs = pr_zxbzs;
+	}
+
+	public Long getPn_b2bid() {
+		return pn_b2bid;
+	}
+
+	public void setPn_b2bid(Long pn_b2bid) {
+		this.pn_b2bid = pn_b2bid;
+	}
+
+	public Long getPn_terminalvenduu() {
+		return pn_terminalvenduu;
+	}
+
+	public void setPn_terminalvenduu(Long pn_terminalvenduu) {
+		this.pn_terminalvenduu = pn_terminalvenduu;
+	}
+
+	public PurchaseNotify map() {
+		PurchaseNotify.Builder builder = PurchaseNotify.newBuilder();
+		builder.setPnId(pn_id);
+		builder.setVeUu(ve_uu);
+		if (null != pn_indate) {
+			builder.setPnIndate(pn_indate.getTime());
+		}
+		if (null != pn_qty) {
+			builder.setPnQty(pn_qty);
+		}
+		if (null != pn_delivery) {
+			builder.setPnDelivery(pn_delivery.getTime());
+		}
+		if (!StringUtils.isEmpty(pn_ordercode)) {
+			builder.setPnOrdercode(pn_ordercode);
+		}
+		if (null != pn_orderdetno) {
+			builder.setPnOrderdetno(pn_orderdetno);
+		}
+		if (!StringUtils.isEmpty(pn_remark)) {
+			builder.setPnRemark(pn_remark);
+		}
+		if (null != pn_endqty) {
+			builder.setPnEndqty(pn_endqty);
+		}
+		if (null != pr_zxbzs) {
+			builder.setPrZxbzs(pr_zxbzs);
+		}
+		if (!NumberUtils.isEmpty(pn_b2bid)) {
+			builder.setPnB2Bid(pn_b2bid);
+		}
+		if (!NumberUtils.isEmpty(pn_terminalvenduu)) {
+			builder.setPnTerminalvenduu(pn_terminalvenduu);
+		}
+		return builder.build();
+	}
+
+	@Override
+	public Object id() {
+		return pn_id;
+	}
+}

+ 445 - 0
uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/po/PurchasePO.java

@@ -0,0 +1,445 @@
+package com.usoftchina.uas.pl.b2b.po;
+
+import com.usoft.b2b.external.erp.order.api.entity.Purchase;
+import com.usoftchina.uas.pl.entity.KeyEntity;
+import com.usoftchina.uas.pl.utils.NumberUtils;
+import com.usoftchina.uas.pl.utils.StringUtils;
+import org.springframework.util.CollectionUtils;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * ERP系统的采购订单
+ * 
+ * @author yingp
+ * 
+ */
+public class PurchasePO implements KeyEntity {
+
+	private Long pu_id;
+	private String pu_code;
+	private Date pu_date;
+	private Long em_uu;
+	private String em_name;
+	private String em_sex;
+	private String em_mobile;
+	private String em_email;
+	private String pu_vendname;
+	private Long ve_uu;
+	private String pu_cop;
+	private Long ve_contactuu;
+	private String ve_contact;
+	private String pu_currency;
+	private Float pu_rate;
+	private String pu_kind; // 采购类型,
+	private String pu_payments;
+	private String pu_remark;
+	private String pu_recordman;
+	private String pu_auditman;
+	private Date pu_indate;
+	private String pu_shipaddresscode;
+	private List<PurchaseDetailPO> purchaseDetails;
+	private Long pu_buyerid;
+	private String pu_receivename;
+	private String pu_receivecode;
+	private String pu_vendcode;
+	private String pu_purpose; // 用途,
+	private String pu_arcustcode; // 买家应收客户,
+	private String pu_shcustcode; // 收货客户,
+	private String pu_refcode; // 销售单号
+	private String pu_custcode; // 客户编号,
+	private String pu_custname; // 客户名称。
+	private Long pu_b2bid; // b2bid
+	/**
+	 * 运输方式
+	 */
+	private String pu_transport;
+
+	public String getPu_vendcode() {
+		return pu_vendcode;
+	}
+
+	public String getPu_purpose() {
+		return pu_purpose;
+	}
+
+	public void setPu_purpose(String pu_purpose) {
+		this.pu_purpose = pu_purpose;
+	}
+
+	public String getPu_arcustcode() {
+		return pu_arcustcode;
+	}
+
+	public void setPu_arcustcode(String pu_arcustcode) {
+		this.pu_arcustcode = pu_arcustcode;
+	}
+
+	public String getPu_shcustcode() {
+		return pu_shcustcode;
+	}
+
+	public void setPu_shcustcode(String pu_shcustcode) {
+		this.pu_shcustcode = pu_shcustcode;
+	}
+
+	public String getPu_refcode() {
+		return pu_refcode;
+	}
+
+	public void setPu_refcode(String pu_refcode) {
+		this.pu_refcode = pu_refcode;
+	}
+
+	public String getPu_custcode() {
+		return pu_custcode;
+	}
+
+	public void setPu_custcode(String pu_custcode) {
+		this.pu_custcode = pu_custcode;
+	}
+
+	public String getPu_custname() {
+		return pu_custname;
+	}
+
+	public void setPu_custname(String pu_custname) {
+		this.pu_custname = pu_custname;
+	}
+
+	public void setPu_vendcode(String pu_vendcode) {
+		this.pu_vendcode = pu_vendcode;
+	}
+
+	public String getPu_code() {
+		return pu_code;
+	}
+
+	public void setPu_code(String pu_code) {
+		this.pu_code = pu_code;
+	}
+
+	public Date getPu_date() {
+		return pu_date;
+	}
+
+	public void setPu_date(Date pu_date) {
+		this.pu_date = pu_date;
+	}
+
+	public Long getEm_uu() {
+		return em_uu;
+	}
+
+	public void setEm_uu(Long em_uu) {
+		this.em_uu = em_uu;
+	}
+
+	public Long getVe_uu() {
+		return ve_uu;
+	}
+
+	public void setVe_uu(Long ve_uu) {
+		this.ve_uu = ve_uu;
+	}
+
+	public String getPu_currency() {
+		return pu_currency;
+	}
+
+	public void setPu_currency(String pu_currency) {
+		this.pu_currency = pu_currency;
+	}
+
+	public Float getPu_rate() {
+		return pu_rate;
+	}
+
+	public void setPu_rate(Float pu_rate) {
+		this.pu_rate = pu_rate;
+	}
+
+	public String getPu_cop() {
+		return pu_cop;
+	}
+
+	public void setPu_cop(String pu_cop) {
+		this.pu_cop = pu_cop;
+	}
+
+	public String getPu_kind() {
+		return pu_kind;
+	}
+
+	public void setPu_kind(String pu_kind) {
+		this.pu_kind = pu_kind;
+	}
+
+	public Long getVe_contactuu() {
+		return ve_contactuu;
+	}
+
+	public void setVe_contactuu(Long ve_contactuu) {
+		this.ve_contactuu = ve_contactuu;
+	}
+
+	public String getVe_contact() {
+		return ve_contact;
+	}
+
+	public void setVe_contact(String ve_contact) {
+		this.ve_contact = ve_contact;
+	}
+
+	public String getPu_payments() {
+		return pu_payments;
+	}
+
+	public void setPu_payments(String pu_payments) {
+		this.pu_payments = pu_payments;
+	}
+
+	public String getPu_remark() {
+		return pu_remark;
+	}
+
+	public void setPu_remark(String pu_remark) {
+		this.pu_remark = pu_remark;
+	}
+
+	public String getPu_recordman() {
+		return pu_recordman;
+	}
+
+	public void setPu_recordman(String pu_recordman) {
+		this.pu_recordman = pu_recordman;
+	}
+
+	public String getPu_auditman() {
+		return pu_auditman;
+	}
+
+	public void setPu_auditman(String pu_auditman) {
+		this.pu_auditman = pu_auditman;
+	}
+
+	public Date getPu_indate() {
+		return pu_indate;
+	}
+
+	public void setPu_indate(Date pu_indate) {
+		this.pu_indate = pu_indate;
+	}
+
+	public String getPu_shipaddresscode() {
+		return pu_shipaddresscode;
+	}
+
+	public void setPu_shipaddresscode(String pu_shipaddresscode) {
+		this.pu_shipaddresscode = pu_shipaddresscode;
+	}
+
+	public List<PurchaseDetailPO> getPurchaseDetails() {
+		return purchaseDetails;
+	}
+
+	public void setPurchaseDetails(List<PurchaseDetailPO> purchaseDetails) {
+		this.purchaseDetails = purchaseDetails;
+	}
+
+	public Long getPu_id() {
+		return pu_id;
+	}
+
+	public void setPu_id(Long pu_id) {
+		this.pu_id = pu_id;
+	}
+
+	public String getEm_name() {
+		return em_name;
+	}
+
+	public void setEm_name(String em_name) {
+		this.em_name = em_name;
+	}
+
+	public String getEm_sex() {
+		return em_sex;
+	}
+
+	public void setEm_sex(String em_sex) {
+		this.em_sex = em_sex;
+	}
+
+	public String getEm_mobile() {
+		return em_mobile;
+	}
+
+	public void setEm_mobile(String em_mobile) {
+		this.em_mobile = em_mobile;
+	}
+
+	public String getEm_email() {
+		return em_email;
+	}
+
+	public void setEm_email(String em_email) {
+		this.em_email = em_email;
+	}
+
+	public String getPu_receivename() {
+		return pu_receivename;
+	}
+
+	public void setPu_receivename(String pu_receivename) {
+		this.pu_receivename = pu_receivename;
+	}
+
+	public String getPu_receivecode() {
+		return pu_receivecode;
+	}
+
+	public void setPu_receivecode(String pu_receivecode) {
+		this.pu_receivecode = pu_receivecode;
+	}
+
+	public Long getPu_buyerid() {
+		return pu_buyerid;
+	}
+
+	public void setPu_buyerid(Long pu_buyerid) {
+		this.pu_buyerid = pu_buyerid;
+	}
+
+	public String getPu_vendname() {
+		return pu_vendname;
+	}
+
+	public void setPu_vendname(String pu_vendname) {
+		this.pu_vendname = pu_vendname;
+	}
+
+	public Long getPu_b2bid() {
+		return pu_b2bid;
+	}
+
+	public void setPu_b2bid(Long pu_b2bid) {
+		this.pu_b2bid = pu_b2bid;
+	}
+
+	public String getPu_transport() {
+		return pu_transport;
+	}
+
+	public void setPu_transport(String pu_transport) {
+		this.pu_transport = pu_transport;
+	}
+
+	/**
+	 * purchase对象转换
+	 *
+	 * @return
+	 */
+	public Purchase map() {
+		Purchase.Builder builder = Purchase.newBuilder();
+		if (!StringUtils.isEmpty(this.getEm_email())) {
+			builder.setEmEmail(this.getEm_email());
+		}
+		if (!StringUtils.isEmpty(this.getEm_mobile())) {
+			builder.setEmMobile(this.getEm_mobile());
+		}
+		if (!StringUtils.isEmpty(this.getEm_name())) {
+			builder.setEmName(this.getEm_name());
+		}
+		if (!StringUtils.isEmpty(this.getEm_sex())) {
+			builder.setEmSex(this.getEm_sex());
+		}
+		if (!NumberUtils.isEmpty(this.getEm_uu())) {
+			builder.setEmUu(this.getEm_uu());
+		}
+		if (!StringUtils.isEmpty(this.getPu_arcustcode())) {
+			builder.setPuArcustcode(this.getPu_arcustcode());
+		}
+		if (!StringUtils.isEmpty(this.getPu_auditman())) {
+			builder.setPuAuditman(this.getPu_auditman());
+		}
+		if (!NumberUtils.isEmpty(this.getPu_b2bid())) {
+			builder.setPuB2Bid(this.getPu_b2bid());
+		}
+		if (!StringUtils.isEmpty(this.getPu_code())) {
+			builder.setPuCode(this.getPu_code());
+		}
+		if (!StringUtils.isEmpty(this.getPu_cop())) {
+			builder.setPuCop(this.getPu_cop());
+		}
+		if (!StringUtils.isEmpty(this.getPu_currency())) {
+			builder.setPuCurrency(this.getPu_currency());
+		}
+		if (!StringUtils.isEmpty(this.getPu_custcode())) {
+			builder.setPuCustcode(this.getPu_custcode());
+		}
+		if (!StringUtils.isEmpty(this.getPu_custname())) {
+			builder.setPuCustname(this.getPu_custname());
+		}
+		if (null != this.getPu_date()) {
+			builder.setPuDate(pu_date.getTime());
+		}
+		if (!NumberUtils.isEmpty(this.getPu_id())) {
+			builder.setPuId(this.getPu_id());
+		}
+		if (!StringUtils.isEmpty(this.getPu_kind())) {
+			builder.setPuKind(this.getPu_kind());
+		}
+		if (!StringUtils.isEmpty(this.getPu_payments())) {
+			builder.setPuPayments(this.getPu_payments());
+		}
+		if (!StringUtils.isEmpty(this.getPu_purpose())) {
+			builder.setPuPurpose(this.getPu_purpose());
+		}
+		if (null != this.getPu_rate()) {
+			builder.setPuRate(this.getPu_rate());
+		}
+		if (!StringUtils.isEmpty(this.getPu_receivecode())) {
+			builder.setPuReceivecode(this.getPu_receivecode());
+		}
+		if (!StringUtils.isEmpty(this.getPu_receivename())) {
+			builder.setPuReceivename(this.getPu_receivename());
+		}
+		if (!StringUtils.isEmpty(this.getPu_refcode())) {
+			builder.setPuRefcode(this.getPu_refcode());
+		}
+		if (!StringUtils.isEmpty(this.getPu_shcustcode())) {
+			builder.setPuShcustcode(this.getPu_shcustcode());
+		}
+		if (!StringUtils.isEmpty(this.getPu_shipaddresscode())) {
+			builder.setPuShipaddresscode(this.getPu_shipaddresscode());
+		}
+		if (!StringUtils.isEmpty(this.getPu_recordman())) {
+			builder.setPuRecordman(this.getPu_recordman());
+		}
+		if (!StringUtils.isEmpty(this.getPu_remark())) {
+			builder.setPuRemark(this.getPu_remark());
+		}
+		if (!NumberUtils.isEmpty(this.getVe_contactuu())) {
+			builder.setVeContactuu(this.getVe_contactuu());
+		}
+		if (!NumberUtils.isEmpty(this.getVe_uu())) {
+			builder.setVeUu(this.getVe_uu());
+		}
+		if (!StringUtils.isEmpty(this.getPu_transport())) {
+			builder.setPuTransport(this.getPu_transport());
+		}
+		if (!CollectionUtils.isEmpty(purchaseDetails)) {
+			purchaseDetails.forEach(detail -> {
+				builder.addPurchaseDetails(detail.map());
+			});
+		}
+		return builder.build();
+	}
+
+	@Override
+	public Object id() {
+		return pu_id;
+	}
+}

+ 173 - 0
uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/po/PurchaseProdInOutDetailPO.java

@@ -0,0 +1,173 @@
+package com.usoftchina.uas.pl.b2b.po;
+
+import com.usoft.b2b.external.erp.deliver.api.entity.PurchaseProdInOut;
+import com.usoftchina.uas.pl.utils.StringUtils;
+
+/**
+ * 采购方角度ERP采购验收单明细
+ *
+ * @author suntg
+ * @date 201541710:32:24
+ */
+public class PurchaseProdInOutDetailPO {
+
+    private Long pd_id;//id
+    private Short pd_detno;//明细行序号
+    private String pd_ordercode;//采购单编号
+    private Short pd_orderdetno;//采购单明细行号
+    private Double pd_inqty;//入库数量
+    private Double pd_outqty;//出库数量
+    private Double pd_orderprice;//采购成本
+    private Double pd_taxrate;//税率
+    private String pd_batchcode;//批号
+    private String pd_remark;//备注
+    private String pd_prodcode;//物料编号
+    private String pd_whname;//仓库名称
+
+    /**
+     * 平台送货单明细id
+     */
+    private Long b2b_si_id;
+
+    public Long getB2b_si_id() {
+        return b2b_si_id;
+    }
+
+    public void setB2b_si_id(Long b2b_si_id) {
+        this.b2b_si_id = b2b_si_id;
+    }
+
+    public String getPd_prodcode() {
+        return pd_prodcode;
+    }
+
+    public void setPd_prodcode(String pd_prodcode) {
+        this.pd_prodcode = pd_prodcode;
+    }
+
+    public Long getPd_id() {
+        return pd_id;
+    }
+
+    public void setPd_id(Long pd_id) {
+        this.pd_id = pd_id;
+    }
+
+    public Short getPd_detno() {
+        return pd_detno;
+    }
+
+    public void setPd_detno(Short pd_detno) {
+        this.pd_detno = pd_detno;
+    }
+
+    public String getPd_ordercode() {
+        return pd_ordercode;
+    }
+
+    public void setPd_ordercode(String pd_ordercode) {
+        this.pd_ordercode = pd_ordercode;
+    }
+
+    public Short getPd_orderdetno() {
+        return pd_orderdetno;
+    }
+
+    public void setPd_orderdetno(Short pd_orderdetno) {
+        this.pd_orderdetno = pd_orderdetno;
+    }
+
+    public Double getPd_inqty() {
+        return pd_inqty;
+    }
+
+    public void setPd_inqty(Double pd_inqty) {
+        this.pd_inqty = pd_inqty;
+    }
+
+    public Double getPd_taxrate() {
+        return pd_taxrate;
+    }
+
+    public void setPd_taxrate(Double pd_taxrate) {
+        this.pd_taxrate = pd_taxrate;
+    }
+
+    public String getPd_batchcode() {
+        return pd_batchcode;
+    }
+
+    public void setPd_batchcode(String pd_batchcode) {
+        this.pd_batchcode = pd_batchcode;
+    }
+
+    public String getPd_remark() {
+        return pd_remark;
+    }
+
+    public void setPd_remark(String pd_remark) {
+        this.pd_remark = pd_remark;
+    }
+
+    public Double getPd_orderprice() {
+        return pd_orderprice;
+    }
+
+    public void setPd_orderprice(Double pd_orderprice) {
+        this.pd_orderprice = pd_orderprice;
+    }
+
+    public Double getPd_outqty() {
+        return pd_outqty;
+    }
+
+    public void setPd_outqty(Double pd_outqty) {
+        this.pd_outqty = pd_outqty;
+    }
+
+    public String getPd_whname() {
+        return pd_whname;
+    }
+
+    public void setPd_whname(String pd_whname) {
+        this.pd_whname = pd_whname;
+    }
+
+    public PurchaseProdInOut.PurchaseProdInOutDetail map() {
+        PurchaseProdInOut.PurchaseProdInOutDetail.Builder builder = PurchaseProdInOut.PurchaseProdInOutDetail.newBuilder();
+        if (null != pd_detno) {
+            builder.setPdDetno(pd_detno);
+        }
+        if (!StringUtils.isEmpty(pd_ordercode)) {
+            builder.setPdOrdercode(pd_ordercode);
+        }
+        if (null != pd_orderdetno) {
+            builder.setPdOrderdetno(pd_orderdetno);
+        }
+        if (null != pd_inqty) {
+            builder.setPdInqty(pd_inqty);
+        }
+        if (null != pd_outqty) {
+            builder.setPdOutqty(pd_outqty);
+        }
+        if (null != pd_orderprice) {
+            builder.setPdOrderprice(pd_orderprice);
+        }
+        if (null != pd_taxrate) {
+            builder.setPdTaxrate(pd_taxrate);
+        }
+        if (!StringUtils.isEmpty(pd_batchcode)) {
+            builder.setPdBatchcode(pd_batchcode);
+        }
+        if (!StringUtils.isEmpty(pd_remark)) {
+            builder.setPdRemark(pd_remark);
+        }
+        if (!StringUtils.isEmpty(pd_prodcode)) {
+            builder.setPdProdcode(pd_prodcode);
+        }
+        if (!StringUtils.isEmpty(pd_whname)) {
+            builder.setPdWhname(pd_whname);
+        }
+        return builder.build();
+    }
+}

+ 269 - 0
uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/po/PurchaseProdInOutPO.java

@@ -0,0 +1,269 @@
+package com.usoftchina.uas.pl.b2b.po;
+
+import com.usoft.b2b.external.erp.deliver.api.entity.PurchaseProdInOut;
+import com.usoftchina.uas.pl.entity.KeyEntity;
+import com.usoftchina.uas.pl.utils.CollectionUtils;
+import com.usoftchina.uas.pl.utils.NumberUtils;
+import com.usoftchina.uas.pl.utils.StringUtils;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 采购方角度ERP采购验收单
+ *
+ * @author suntg
+ * @date 201541710:32:24
+ */
+public class PurchaseProdInOutPO implements KeyEntity {
+
+    /**
+     * erp出入库单据的id
+     */
+    private Long pi_id;
+
+    /**
+     * erp出入库单据单号
+     */
+    private String pi_inoutno;
+
+    /**
+     * 供应商UU
+     */
+    private Long pi_vendoruu;
+
+    /**
+     * 币别
+     */
+    private String pi_currency;
+
+    /**
+     * 汇率
+     */
+    private Float pi_rate;
+
+    /**
+     * 付款方式
+     */
+    private String pi_payment;
+
+    /**
+     * 运输方式
+     */
+    private String pi_transport;
+
+    /**
+     * 备注
+     */
+    private String pi_remark;
+
+    /**
+     * 过账人
+     */
+    private String pi_inoutman;
+
+    /**
+     * 过账日期
+     */
+    private Date pi_date;
+
+    /**
+     * 送货单号
+     */
+    private String pi_sendcode;
+
+    /**
+     * 应付供应商名
+     */
+    private String pi_receivename;
+
+    /**
+     * 应付供应商编号
+     */
+    private String pi_receivecode;
+
+    /**
+     * 明细
+     */
+    private List<PurchaseProdInOutDetailPO> details;
+
+    /**
+     * b2bId
+     */
+    private Long pi_b2b_id;
+
+    public Long getPi_id() {
+        return pi_id;
+    }
+
+    public void setPi_id(Long pi_id) {
+        this.pi_id = pi_id;
+    }
+
+    public String getPi_inoutno() {
+        return pi_inoutno;
+    }
+
+    public void setPi_inoutno(String pi_inoutno) {
+        this.pi_inoutno = pi_inoutno;
+    }
+
+    public Long getPi_vendoruu() {
+        return pi_vendoruu;
+    }
+
+    public void setPi_vendoruu(Long pi_vendoruu) {
+        this.pi_vendoruu = pi_vendoruu;
+    }
+
+    public String getPi_currency() {
+        return pi_currency;
+    }
+
+    public void setPi_currency(String pi_currency) {
+        this.pi_currency = pi_currency;
+    }
+
+    public Float getPi_rate() {
+        return pi_rate;
+    }
+
+    public void setPi_rate(Float pi_rate) {
+        this.pi_rate = pi_rate;
+    }
+
+    public String getPi_payment() {
+        return pi_payment;
+    }
+
+    public void setPi_payment(String pi_payment) {
+        this.pi_payment = pi_payment;
+    }
+
+    public String getPi_transport() {
+        return pi_transport;
+    }
+
+    public void setPi_transport(String pi_transport) {
+        this.pi_transport = pi_transport;
+    }
+
+    public String getPi_remark() {
+        return pi_remark;
+    }
+
+    public void setPi_remark(String pi_remark) {
+        this.pi_remark = pi_remark;
+    }
+
+    public String getPi_inoutman() {
+        return pi_inoutman;
+    }
+
+    public void setPi_inoutman(String pi_inoutman) {
+        this.pi_inoutman = pi_inoutman;
+    }
+
+    public Date getPi_date() {
+        return pi_date;
+    }
+
+    public void setPi_date(Date pi_date) {
+        this.pi_date = pi_date;
+    }
+
+    public String getPi_sendcode() {
+        return pi_sendcode;
+    }
+
+    public void setPi_sendcode(String pi_sendcode) {
+        this.pi_sendcode = pi_sendcode;
+    }
+
+    public String getPi_receivename() {
+        return pi_receivename;
+    }
+
+    public void setPi_receivename(String pi_receivename) {
+        this.pi_receivename = pi_receivename;
+    }
+
+    public String getPi_receivecode() {
+        return pi_receivecode;
+    }
+
+    public void setPi_receivecode(String pi_receivecode) {
+        this.pi_receivecode = pi_receivecode;
+    }
+
+    public List<PurchaseProdInOutDetailPO> getDetails() {
+        return details;
+    }
+
+    public void setDetails(List<PurchaseProdInOutDetailPO> details) {
+        this.details = details;
+    }
+
+    public Long getPi_b2b_id() {
+        return pi_b2b_id;
+    }
+
+    public void setPi_b2b_id(Long pi_b2b_id) {
+        this.pi_b2b_id = pi_b2b_id;
+    }
+
+    public PurchaseProdInOut map() {
+        PurchaseProdInOut.Builder builder = PurchaseProdInOut.newBuilder();
+        if (!NumberUtils.isEmpty(pi_id)) {
+            builder.setPiId(pi_id);
+        }
+        if (!StringUtils.isEmpty(pi_inoutno)) {
+            builder.setPiInoutno(pi_inoutno);
+        }
+        if (!NumberUtils.isEmpty(pi_vendoruu)) {
+            builder.setPiVendoruu(pi_vendoruu);
+        }
+        if (!StringUtils.isEmpty(pi_currency)) {
+            builder.setPiCurrency(pi_currency);
+        }
+        if (null != pi_rate) {
+            builder.setPiRate(pi_rate);
+        }
+        if (!StringUtils.isEmpty(pi_payment)) {
+            builder.setPiPayment(pi_payment);
+        }
+        if (!StringUtils.isEmpty(pi_transport)) {
+            builder.setPiTransport(pi_transport);
+        }
+        if (!StringUtils.isEmpty(pi_remark)) {
+            builder.setPiRemark(pi_remark);
+        }
+        if (!StringUtils.isEmpty(pi_inoutman)) {
+            builder.setPiInoutman(pi_inoutman);
+        }
+        if (null != pi_date) {
+            builder.setPiDate(pi_date.getTime());
+        }
+        if (!StringUtils.isEmpty(pi_sendcode)) {
+            builder.setPiSendcode(pi_sendcode);
+        }
+        if (!StringUtils.isEmpty(pi_receivecode)) {
+            builder.setPiReceivecode(pi_receivecode);
+        }
+        if (!StringUtils.isEmpty(pi_receivename)) {
+            builder.setPiReceivename(pi_receivename);
+        }
+        if (!NumberUtils.isEmpty(pi_b2b_id)) {
+            builder.setPiB2BId(pi_b2b_id);
+        }
+        if (!CollectionUtils.isEmpty(details)) {
+            details.forEach(detail -> builder.addDetails(detail.map()));
+        }
+        return builder.build();
+    }
+
+    @Override
+    public Object id() {
+        return pi_id;
+    }
+}

+ 150 - 0
uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/po/PurchaseReplyPO.java

@@ -0,0 +1,150 @@
+package com.usoftchina.uas.pl.b2b.po;
+
+import com.usoft.b2b.external.erp.order.api.entity.PurchaseReply;
+import com.usoftchina.uas.pl.entity.KeyEntity;
+import com.usoftchina.uas.pl.utils.NumberUtils;
+import com.usoftchina.uas.pl.utils.StringUtils;
+
+import java.util.Date;
+
+/**
+ * 采购订单明细回复记录
+ *
+ * @author yingp
+ */
+public class PurchaseReplyPO implements KeyEntity {
+
+    private Integer pr_id;
+    private Double pr_qty;
+    private Date pr_delivery;
+    private String pr_remark;
+    private String pr_pucode;
+    private Integer pr_pddetno;
+    private Date pr_date;
+    private String pr_recorder;
+    /**
+     * 平台里面的ID,作为唯一标志,防止重复写入回复记录
+     */
+    private Long b2b_pr_id;
+    private String pr_type;
+
+    public Double getPr_qty() {
+        return pr_qty;
+    }
+
+    public void setPr_qty(Double pr_qty) {
+        this.pr_qty = pr_qty;
+    }
+
+    public Date getPr_delivery() {
+        return pr_delivery;
+    }
+
+    public void setPr_delivery(Date pr_delivery) {
+        this.pr_delivery = pr_delivery;
+    }
+
+    public String getPr_remark() {
+        return pr_remark;
+    }
+
+    public void setPr_remark(String pr_remark) {
+        this.pr_remark = pr_remark;
+    }
+
+    public String getPr_pucode() {
+        return pr_pucode;
+    }
+
+    public void setPr_pucode(String pr_pucode) {
+        this.pr_pucode = pr_pucode;
+    }
+
+    public Date getPr_date() {
+        return pr_date;
+    }
+
+    public void setPr_date(Date pr_date) {
+        this.pr_date = pr_date;
+    }
+
+    public String getPr_recorder() {
+        return pr_recorder;
+    }
+
+    public void setPr_recorder(String pr_recorder) {
+        this.pr_recorder = pr_recorder;
+    }
+
+    public String getPr_type() {
+        return pr_type;
+    }
+
+    public void setPr_type(String pr_type) {
+        this.pr_type = pr_type;
+    }
+
+    public Integer getPr_pddetno() {
+        return pr_pddetno;
+    }
+
+    public void setPr_pddetno(Integer pr_pddetno) {
+        this.pr_pddetno = pr_pddetno;
+    }
+
+    public Long getB2b_pr_id() {
+        return b2b_pr_id;
+    }
+
+    public void setB2b_pr_id(Long b2b_pr_id) {
+        this.b2b_pr_id = b2b_pr_id;
+    }
+
+    public Integer getPr_id() {
+        return pr_id;
+    }
+
+    public void setPr_id(Integer pr_id) {
+        this.pr_id = pr_id;
+    }
+
+    public PurchaseReply map() {
+        PurchaseReply.Builder builder = PurchaseReply.newBuilder();
+        if (null != pr_id) {
+            builder.setPrId(pr_id);
+        }
+        if (null != pr_qty) {
+            builder.setPrQty(pr_qty);
+        }
+        if (null != pr_delivery) {
+            builder.setPrDelivery(pr_delivery.getTime());
+        }
+        if (!StringUtils.isEmpty(pr_remark)) {
+            builder.setPrRemark(pr_remark);
+        }
+        if (!StringUtils.isEmpty(pr_pucode)) {
+            builder.setPrPucode(pr_pucode);
+        }
+        if (null != pr_pddetno) {
+            builder.setPrPddetno(pr_pddetno);
+        }
+        if (null != pr_date) {
+            builder.setPrDate(pr_date.getTime());
+        }
+        if (!StringUtils.isEmpty(pr_recorder)) {
+            builder.setPrRecorder(pr_recorder);
+        }
+        if (!NumberUtils.isEmpty(b2b_pr_id)) {
+            builder.setB2BPrId(b2b_pr_id);
+        }
+        if (!StringUtils.isEmpty(pr_type)) {
+            builder.setPrType(pr_type);
+        }
+        return builder.build();
+    }
+
+    @Override
+    public Object id() {
+        return pr_id;
+    }
+}

+ 173 - 0
uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/po/SaleCheckDetailPO.java

@@ -0,0 +1,173 @@
+package com.usoftchina.uas.pl.b2b.po;
+
+import com.usoft.b2b.external.erp.reconciliation.api.entity.PurchaseApCheck;
+import com.usoftchina.uas.pl.utils.NumberUtils;
+import com.usoftchina.uas.pl.utils.StringUtils;
+
+/**
+ * @author yingp
+ */
+public class SaleCheckDetailPO {
+
+    private Integer ad_detno; // 明细行号
+    private Long ad_prid;// 客户物料ID #
+    private String ad_inoutno; // 客户出入库单号   ad_inoutno 出入库单号
+    private String ad_orderclass; // 客户出入库类型 #
+    private Long ad_orderdetno; // 客户出入库序号 #
+    private Double ad_price; // 单价
+    private Double ad_b2bqty; // 对账数量
+    private Double ad_b2bamount; // 本次对账金额
+    private Double ad_custcheckqty; // 客户确认数量 #
+    private String ad_remark; // 备注
+    private Long ad_id;// id #
+    private Long ad_apid; // 关联Id  #
+    private Integer ad_status; // 对账状态 #
+
+    public Integer getAd_detno() {
+        return ad_detno;
+    }
+
+    public void setAd_detno(Integer ad_detno) {
+        this.ad_detno = ad_detno;
+    }
+
+    public Long getAd_prid() {
+        return ad_prid;
+    }
+
+    public void setAd_prid(Long ad_prid) {
+        this.ad_prid = ad_prid;
+    }
+
+    public String getAd_inoutno() {
+        return ad_inoutno;
+    }
+
+    public void setAd_inoutno(String ad_inoutno) {
+        this.ad_inoutno = ad_inoutno;
+    }
+
+    public String getAd_orderclass() {
+        return ad_orderclass;
+    }
+
+    public void setAd_orderclass(String ad_orderclass) {
+        this.ad_orderclass = ad_orderclass;
+    }
+
+    public Long getAd_orderdetno() {
+        return ad_orderdetno;
+    }
+
+    public void setAd_orderdetno(Long ad_orderdetno) {
+        this.ad_orderdetno = ad_orderdetno;
+    }
+
+    public Double getAd_price() {
+        return ad_price;
+    }
+
+    public void setAd_price(Double ad_price) {
+        this.ad_price = ad_price;
+    }
+
+    public Double getAd_b2bqty() {
+        return ad_b2bqty;
+    }
+
+    public void setAd_b2bqty(Double ad_b2bqty) {
+        this.ad_b2bqty = ad_b2bqty;
+    }
+
+    public Double getAd_b2bamount() {
+        return ad_b2bamount;
+    }
+
+    public void setAd_b2bamount(Double ad_b2bamount) {
+        this.ad_b2bamount = ad_b2bamount;
+    }
+
+    public Double getAd_custcheckqty() {
+        return ad_custcheckqty;
+    }
+
+    public void setAd_custcheckqty(Double ad_custcheckqty) {
+        this.ad_custcheckqty = ad_custcheckqty;
+    }
+
+    public String getAd_remark() {
+        return ad_remark;
+    }
+
+    public void setAd_remark(String ad_remark) {
+        this.ad_remark = ad_remark;
+    }
+
+    public Long getAd_id() {
+        return ad_id;
+    }
+
+    public void setAd_id(Long ad_id) {
+        this.ad_id = ad_id;
+    }
+
+    public Long getAd_apid() {
+        return ad_apid;
+    }
+
+    public void setAd_apid(Long ad_apid) {
+        this.ad_apid = ad_apid;
+    }
+
+    public Integer getAd_status() {
+        return ad_status;
+    }
+
+    public void setAd_status(Integer ad_status) {
+        this.ad_status = ad_status;
+    }
+
+    public PurchaseApCheck.APCheckDetail map() {
+        PurchaseApCheck.APCheckDetail.Builder builder = PurchaseApCheck.APCheckDetail.newBuilder();
+        if (null != ad_detno) {
+            builder.setAdDetno(ad_detno);
+        }
+        if (!NumberUtils.isEmpty(ad_prid)) {
+            builder.setAdPrid(ad_prid);
+        }
+        if (!StringUtils.isEmpty(ad_inoutno)) {
+            builder.setAdInoutno(ad_inoutno);
+        }
+        if (!StringUtils.isEmpty(ad_orderclass)) {
+            builder.setAdOrderclass(ad_orderclass);
+        }
+        if (null != ad_orderdetno) {
+            builder.setAdOrderdetno(ad_orderdetno);
+        }
+        if (null != ad_price) {
+            builder.setAdPrice(ad_price);
+        }
+        if (null != ad_b2bqty) {
+            builder.setAdB2Bqty(ad_b2bqty);
+        }
+        if (null != ad_b2bamount) {
+            builder.setAdB2Bamount(ad_b2bamount);
+        }
+        if (null != ad_custcheckqty) {
+            builder.setAdCustcheckqty(ad_custcheckqty);
+        }
+        if (!StringUtils.isEmpty(ad_remark)) {
+            builder.setAdRemark(ad_remark);
+        }
+        if (!NumberUtils.isEmpty(ad_id)) {
+            builder.setAdId(ad_id);
+        }
+        if (!NumberUtils.isEmpty(ad_apid)) {
+            builder.setAdApid(ad_apid);
+        }
+        if (null != ad_status) {
+            builder.setAdStatus(ad_status);
+        }
+        return builder.build();
+    }
+}

+ 275 - 0
uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/po/SaleCheckPO.java

@@ -0,0 +1,275 @@
+package com.usoftchina.uas.pl.b2b.po;
+
+import com.usoft.b2b.external.erp.reconciliation.api.entity.PurchaseApCheck;
+import com.usoftchina.uas.pl.entity.KeyEntity;
+import com.usoftchina.uas.pl.utils.CollectionUtils;
+import com.usoftchina.uas.pl.utils.NumberUtils;
+import com.usoftchina.uas.pl.utils.StringUtils;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 客户应付对账单
+ *
+ * @author aof
+ * @date 2015127
+ */
+public class SaleCheckPO implements KeyEntity {
+    private Long ac_id;//主键ID
+    private Long ac_b2bid;
+    private Date ac_fromdate; // 对账起始日期
+    private Date ac_todate; // 对账截止日期
+    private Date ac_date; // 录单日期
+    private String ac_recorder;//录单人
+    private Date ac_apdate; // 应付日期
+    private String ac_checkstatus;//对账状态
+    private String ac_remark;// 备注
+    private Date ac_commitdate;//提交日期  #
+    private Double ac_checkamount; // 对账金额
+    private String ac_currency; // 币别
+    private Double ac_rate; // 汇率
+    private String ac_paymentname; // 收款方式
+    private Long ac_custuu;//客户UU #
+    private Long ac_enuu;//供应商UU  #
+    private String ac_code; // 单据编号
+    private String ac_confirmstatus;//回复状态
+    private String ac_reason;//回复平台原因
+    private List<SaleCheckDetailPO> details; // 明细
+    private String ac_status;
+
+    public String getAc_reason() {
+        return ac_reason;
+    }
+
+    public void setAc_reason(String ac_reason) {
+        this.ac_reason = ac_reason;
+    }
+
+    public Long getAc_id() {
+        return ac_id;
+    }
+
+    public void setAc_id(Long ac_id) {
+        this.ac_id = ac_id;
+    }
+
+    public String getAc_confirmstatus() {
+        return ac_confirmstatus;
+    }
+
+    public void setAc_confirmstatus(String ac_confirmstatus) {
+        this.ac_confirmstatus = ac_confirmstatus;
+    }
+
+    public Long getAc_b2bid() {
+        return ac_b2bid;
+    }
+
+    public void setAc_b2bid(Long ac_b2bid) {
+        this.ac_b2bid = ac_b2bid;
+    }
+
+    public Date getAc_fromdate() {
+        return ac_fromdate;
+    }
+
+    public void setAc_fromdate(Date ac_fromdate) {
+        this.ac_fromdate = ac_fromdate;
+    }
+
+    public Date getAc_todate() {
+        return ac_todate;
+    }
+
+    public void setAc_todate(Date ac_todate) {
+        this.ac_todate = ac_todate;
+    }
+
+    public Date getAc_date() {
+        return ac_date;
+    }
+
+    public void setAc_date(Date ac_date) {
+        this.ac_date = ac_date;
+    }
+
+    public String getAc_recorder() {
+        return ac_recorder;
+    }
+
+    public void setAc_recorder(String ac_recorder) {
+        this.ac_recorder = ac_recorder;
+    }
+
+    public Date getAc_apdate() {
+        return ac_apdate;
+    }
+
+    public void setAc_apdate(Date ac_apdate) {
+        this.ac_apdate = ac_apdate;
+    }
+
+    public String getAc_checkstatus() {
+        return ac_checkstatus;
+    }
+
+    public void setAc_checkstatus(String ac_checkstatus) {
+        this.ac_checkstatus = ac_checkstatus;
+    }
+
+    public String getAc_remark() {
+        return ac_remark;
+    }
+
+    public void setAc_remark(String ac_remark) {
+        this.ac_remark = ac_remark;
+    }
+
+    public Date getAc_commitdate() {
+        return ac_commitdate;
+    }
+
+    public void setAc_commitdate(Date ac_commitdate) {
+        this.ac_commitdate = ac_commitdate;
+    }
+
+    public Double getAc_checkamount() {
+        return ac_checkamount;
+    }
+
+    public void setAc_checkamount(Double ac_checkamount) {
+        this.ac_checkamount = ac_checkamount;
+    }
+
+    public String getAc_currency() {
+        return ac_currency;
+    }
+
+    public void setAc_currency(String ac_currency) {
+        this.ac_currency = ac_currency;
+    }
+
+    public Double getAc_rate() {
+        return ac_rate;
+    }
+
+    public void setAc_rate(Double ac_rate) {
+        this.ac_rate = ac_rate;
+    }
+
+    public String getAc_paymentname() {
+        return ac_paymentname;
+    }
+
+    public void setAc_paymentname(String ac_paymentname) {
+        this.ac_paymentname = ac_paymentname;
+    }
+
+    public Long getAc_custuu() {
+        return ac_custuu;
+    }
+
+    public void setAc_custuu(Long ac_custuu) {
+        this.ac_custuu = ac_custuu;
+    }
+
+    public Long getAc_enuu() {
+        return ac_enuu;
+    }
+
+    public void setAc_enuu(Long ac_enuu) {
+        this.ac_enuu = ac_enuu;
+    }
+
+    public String getAc_code() {
+        return ac_code;
+    }
+
+    public void setAc_code(String ac_code) {
+        this.ac_code = ac_code;
+    }
+
+    public List<SaleCheckDetailPO> getDetails() {
+        return details;
+    }
+
+    public void setDetails(List<SaleCheckDetailPO> details) {
+        this.details = details;
+    }
+
+    public String getAc_status() {
+        return ac_status;
+    }
+
+    public void setAc_status(String ac_status) {
+        this.ac_status = ac_status;
+    }
+
+    public PurchaseApCheck map() {
+        PurchaseApCheck.Builder builder = PurchaseApCheck.newBuilder();
+        if (!NumberUtils.isEmpty(ac_b2bid)) {
+            builder.setAcB2Bid(ac_b2bid);
+        }
+        if (null != ac_fromdate) {
+            builder.setAcFromdate(ac_fromdate.getTime());
+        }
+        if (null != ac_todate) {
+            builder.setAcTodate(ac_todate.getTime());
+        }
+        if (null != ac_date) {
+            builder.setAcRecorddate(ac_date.getTime());
+        }
+        if (!StringUtils.isEmpty(ac_recorder)) {
+            builder.setAcRecorder(ac_recorder);
+        }
+        if (null != ac_apdate) {
+            builder.setAcApdate(ac_apdate.getTime());
+        }
+        if (!StringUtils.isEmpty(ac_checkstatus)) {
+            builder.setAcCheckstatus(ac_checkstatus);
+        }
+        if (!StringUtils.isEmpty(ac_remark)) {
+            builder.setAcRemark(ac_remark);
+        }
+        if (null != ac_commitdate) {
+            builder.setAcCommitdate(ac_commitdate.getTime());
+        }
+        if (null != ac_checkamount) {
+            builder.setAcCheckamount(ac_checkamount);
+        }
+        if (!StringUtils.isEmpty(ac_currency)) {
+            builder.setAcCurrency(ac_currency);
+        }
+        if (null != ac_rate) {
+            builder.setAcRate(ac_rate);
+        }
+        if (!StringUtils.isEmpty(ac_paymentname)) {
+            builder.setAcPaymentname(ac_paymentname);
+        }
+        if (!NumberUtils.isEmpty(ac_custuu)) {
+            builder.setAcCustuu(ac_custuu);
+        }
+        if (!NumberUtils.isEmpty(ac_enuu)) {
+            builder.setAcEnuu(ac_enuu);
+        }
+        if (!StringUtils.isEmpty(ac_code)) {
+            builder.setAcCode(ac_code);
+        }
+        if (!StringUtils.isEmpty(ac_confirmstatus)) {
+            builder.setAcConfirmstatus(ac_confirmstatus);
+        }
+        if (!StringUtils.isEmpty(ac_reason)) {
+            builder.setAcReason(ac_reason);
+        }
+        if (!CollectionUtils.isEmpty(details)) {
+            details.forEach(detail -> builder.addDetails(detail.map()));
+        }
+        return builder.build();
+    }
+
+    @Override
+    public Object id() {
+        return ac_id;
+    }
+}

+ 86 - 0
uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/po/SaleDownChangeReplyPO.java

@@ -0,0 +1,86 @@
+package com.usoftchina.uas.pl.b2b.po;
+
+import com.usoft.b2b.external.erp.order.api.entity.SaleDownChangeReply;
+import com.usoftchina.uas.pl.entity.KeyEntity;
+import com.usoftchina.uas.pl.utils.Const;
+import com.usoftchina.uas.pl.utils.StringUtils;
+
+public class SaleDownChangeReplyPO implements KeyEntity {
+
+	private long b2b_pc_id;
+	private int sc_id;
+	private String sc_code;
+
+	public long getB2b_pc_id() {
+		return b2b_pc_id;
+	}
+
+	public void setB2b_pc_id(long b2b_pc_id) {
+		this.b2b_pc_id = b2b_pc_id;
+	}
+
+	/**
+	 * 供应商是否同意了变更请求(1,0)
+	 */
+	private Short sc_agreed;
+	/**
+	 * 供应商的回复备注
+	 */
+	private String sc_replyremark;
+
+	public String getSc_code() {
+		return sc_code;
+	}
+
+	public void setSc_code(String sc_code) {
+		this.sc_code = sc_code;
+	}
+
+	public int getSc_id() {
+		return sc_id;
+	}
+
+	public void setSc_id(int sc_id) {
+		this.sc_id = sc_id;
+	}
+
+	public Short getSc_agreed() {
+		return sc_agreed == null ? Const.NO : (short)(-1*Math.abs(sc_agreed));
+	}
+
+	public void setSc_agreed(Short sc_agreed) {
+		this.sc_agreed = sc_agreed;
+	}
+
+	public String getSc_replyremark() {
+		return sc_replyremark;
+	}
+
+	public void setSc_replyremark(String sc_replyremark) {
+		this.sc_replyremark = sc_replyremark;
+	}
+
+	public boolean isAgreed() {
+		return this.sc_agreed != null && Const.YES == Math.abs(this.sc_agreed);
+	}
+
+	public SaleDownChangeReply map() {
+		SaleDownChangeReply.Builder builder = SaleDownChangeReply.newBuilder();
+		builder.setB2BPcId(b2b_pc_id);
+		if (!StringUtils.isEmpty(sc_code)) {
+			builder.setScCode(sc_code);
+		}
+		if (null != sc_agreed) {
+			builder.setScAgreed(sc_agreed);
+		}
+		if (!StringUtils.isEmpty(sc_replyremark)) {
+			builder.setScReplyremark(sc_replyremark);
+		}
+		return builder.build();
+	}
+
+	@Override
+	public Object id() {
+		return sc_id;
+	}
+}

+ 86 - 0
uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/po/SaleOutDetailPO.java

@@ -0,0 +1,86 @@
+package com.usoftchina.uas.pl.b2b.po;
+
+import com.usoft.b2b.external.erp.deliver.api.entity.SaleOut;
+import com.usoftchina.uas.pl.utils.NumberUtils;
+
+/**
+ * 卖家ERP系统的发货单明细
+ * 
+ * @author yingp
+ * 
+ */
+public class SaleOutDetailPO {
+
+	private short pd_pdno;
+	private Double pd_outqty;
+	private Double pd_sendprice;
+	private Long b2b_pn_id;
+	private Long pd_noticeid;
+	private Long pd_orderid;
+
+	public short getPd_pdno() {
+		return pd_pdno;
+	}
+
+	public void setPd_pdno(short pd_pdno) {
+		this.pd_pdno = pd_pdno;
+	}
+
+	public Double getPd_outqty() {
+		return pd_outqty;
+	}
+
+	public void setPd_outqty(Double pd_outqty) {
+		this.pd_outqty = pd_outqty;
+	}
+
+	public Double getPd_sendprice() {
+		return pd_sendprice;
+	}
+
+	public void setPd_sendprice(Double pd_sendprice) {
+		this.pd_sendprice = pd_sendprice;
+	}
+
+	public Long getB2b_pn_id() {
+		return b2b_pn_id;
+	}
+
+	public void setB2b_pn_id(Long b2b_pn_id) {
+		this.b2b_pn_id = b2b_pn_id;
+	}
+
+	public Long getPd_orderid() {
+		return pd_orderid;
+	}
+
+	public void setPd_orderid(Long pd_orderid) {
+		this.pd_orderid = pd_orderid;
+	}
+
+	public Long getPd_noticeid() {
+		return pd_noticeid;
+	}
+
+	public void setPd_noticeid(Long pd_noticeid) {
+		this.pd_noticeid = pd_noticeid;
+	}
+
+	public SaleOut.SaleOutDetail map() {
+		SaleOut.SaleOutDetail.Builder builder = SaleOut.SaleOutDetail.newBuilder();
+		builder.setPdPdno(pd_pdno);
+		if (null != pd_outqty) {
+			builder.setPdOutqty(pd_outqty);
+		}
+		if (null != pd_sendprice) {
+			builder.setPdSendprice(pd_sendprice);
+		}
+		if (!NumberUtils.isEmpty(pd_orderid)) {
+			builder.setPdOrderid(pd_orderid);
+		}
+		if (!NumberUtils.isEmpty(b2b_pn_id)) {
+			builder.setB2BPnId(b2b_pn_id);
+		}
+		return builder.build();
+	}
+}

+ 170 - 0
uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/po/SaleOutPO.java

@@ -0,0 +1,170 @@
+package com.usoftchina.uas.pl.b2b.po;
+
+import com.usoft.b2b.external.erp.deliver.api.entity.SaleOut;
+import com.usoftchina.uas.pl.entity.KeyEntity;
+import com.usoftchina.uas.pl.utils.CollectionUtils;
+import com.usoftchina.uas.pl.utils.NumberUtils;
+import com.usoftchina.uas.pl.utils.StringUtils;
+
+import java.util.List;
+
+/**
+ * 卖家ERP系统的发货单
+ * 
+ * @author yingp
+ * 
+ */
+public class SaleOutPO implements KeyEntity {
+
+	private Integer pi_id;
+	private Long b2b_ss_id;
+	private String pi_inoutno;
+	private String pi_currency;
+	private Float pi_rate;
+	private Long cu_uu;
+	private Long cu_contactuu;
+	private String pi_payment;
+	private String pi_remark;
+	private String pi_recordman;
+	private String pi_auditman;
+	private List<SaleOutDetailPO> details;
+
+	public Integer getPi_id() {
+		return pi_id;
+	}
+
+	public void setPi_id(Integer pi_id) {
+		this.pi_id = pi_id;
+	}
+
+	public String getPi_inoutno() {
+		return pi_inoutno;
+	}
+
+	public void setPi_inoutno(String pi_inoutno) {
+		this.pi_inoutno = pi_inoutno;
+	}
+
+	public Long getCu_uu() {
+		return cu_uu;
+	}
+
+	public void setCu_uu(Long cu_uu) {
+		this.cu_uu = cu_uu;
+	}
+
+	public List<SaleOutDetailPO> getDetails() {
+		return details;
+	}
+
+	public void setDetails(List<SaleOutDetailPO> details) {
+		this.details = details;
+	}
+
+	public Long getB2b_ss_id() {
+		return b2b_ss_id;
+	}
+
+	public void setB2b_ss_id(Long b2b_ss_id) {
+		this.b2b_ss_id = b2b_ss_id;
+	}
+
+	public String getPi_currency() {
+		return pi_currency;
+	}
+
+	public void setPi_currency(String pi_currency) {
+		this.pi_currency = pi_currency;
+	}
+
+	public Float getPi_rate() {
+		return pi_rate;
+	}
+
+	public void setPi_rate(Float pi_rate) {
+		this.pi_rate = pi_rate;
+	}
+
+	public Long getCu_contactuu() {
+		return cu_contactuu;
+	}
+
+	public void setCu_contactuu(Long cu_contactuu) {
+		this.cu_contactuu = cu_contactuu;
+	}
+
+	public String getPi_payment() {
+		return pi_payment;
+	}
+
+	public void setPi_payment(String pi_payment) {
+		this.pi_payment = pi_payment;
+	}
+
+	public String getPi_remark() {
+		return pi_remark;
+	}
+
+	public void setPi_remark(String pi_remark) {
+		this.pi_remark = pi_remark;
+	}
+
+	public String getPi_recordman() {
+		return pi_recordman;
+	}
+
+	public void setPi_recordman(String pi_recordman) {
+		this.pi_recordman = pi_recordman;
+	}
+
+	public String getPi_auditman() {
+		return pi_auditman;
+	}
+
+	public void setPi_auditman(String pi_auditman) {
+		this.pi_auditman = pi_auditman;
+	}
+
+	public SaleOut map() {
+		SaleOut.Builder builder = SaleOut.newBuilder();
+		if (!NumberUtils.isEmpty(b2b_ss_id)) {
+			builder.setB2BSsId(b2b_ss_id);
+		}
+		if (!StringUtils.isEmpty(pi_inoutno)) {
+			builder.setPiInoutno(pi_inoutno);
+		}
+		if (null != pi_currency) {
+			builder.setPiCurrency(pi_currency);
+		}
+		if (null != pi_rate) {
+			builder.setPiRate(pi_rate);
+		}
+		if (null != cu_uu) {
+			builder.setCuUu(cu_uu);
+		}
+		if (null != cu_contactuu) {
+			builder.setCuContactuu(cu_contactuu);
+		}
+		if (!StringUtils.isEmpty(pi_payment)) {
+			builder.setPiPayment(pi_payment);
+		}
+		if (!StringUtils.isEmpty(pi_remark)) {
+			builder.setPiRemark(pi_remark);
+		}
+		if (!StringUtils.isEmpty(pi_recordman)) {
+			builder.setPiRecordman(pi_recordman);
+		}
+		if (!StringUtils.isEmpty(pi_auditman)) {
+			builder.setPiAuditman(pi_auditman);
+		}
+		if (!CollectionUtils.isEmpty(details)) {
+			details.forEach(detail -> builder.addDetails(detail.map()));
+		}
+		return builder.build();
+	}
+
+	@Override
+	public Object id() {
+		return pi_id;
+	}
+}

+ 165 - 0
uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/po/SaleReplyPO.java

@@ -0,0 +1,165 @@
+package com.usoftchina.uas.pl.b2b.po;
+
+import com.usoft.b2b.external.erp.order.api.entity.SaleReply;
+import com.usoftchina.uas.pl.entity.KeyEntity;
+import com.usoftchina.uas.pl.utils.StringUtils;
+
+import java.util.Date;
+
+/**
+ * SaleDown明细回复记录
+ * 
+ * @author yingp
+ * 
+ */
+public class SaleReplyPO implements KeyEntity {
+
+	private int sr_id;
+	private Double sr_qty;
+	private Date sr_delivery;
+	private String sr_remark;
+	private String sr_sacode;
+	private short sr_sddetno;
+	private Date sr_date;
+	private String sr_recorder;
+	private long cu_uu;
+	private Long b2b_pd_id;
+	private Long b2b_pr_id;
+	private String sr_type;
+
+	public int getSr_id() {
+		return sr_id;
+	}
+
+	public void setSr_id(int sr_id) {
+		this.sr_id = sr_id;
+	}
+
+	public Double getSr_qty() {
+		return sr_qty;
+	}
+
+	public void setSr_qty(Double sr_qty) {
+		this.sr_qty = sr_qty;
+	}
+
+	public Date getSr_delivery() {
+		return sr_delivery;
+	}
+
+	public void setSr_delivery(Date sr_delivery) {
+		this.sr_delivery = sr_delivery;
+	}
+
+	public String getSr_remark() {
+		return sr_remark;
+	}
+
+	public void setSr_remark(String sr_remark) {
+		this.sr_remark = sr_remark;
+	}
+
+	public String getSr_sacode() {
+		return sr_sacode;
+	}
+
+	public void setSr_sacode(String sr_sacode) {
+		this.sr_sacode = sr_sacode;
+	}
+
+	public short getSr_sddetno() {
+		return sr_sddetno;
+	}
+
+	public void setSr_sddetno(short sr_sddetno) {
+		this.sr_sddetno = sr_sddetno;
+	}
+
+	public Date getSr_date() {
+		return sr_date;
+	}
+
+	public void setSr_date(Date sr_date) {
+		this.sr_date = sr_date;
+	}
+
+	public String getSr_recorder() {
+		return sr_recorder;
+	}
+
+	public void setSr_recorder(String sr_recorder) {
+		this.sr_recorder = sr_recorder;
+	}
+
+	public long getCu_uu() {
+		return cu_uu;
+	}
+
+	public void setCu_uu(long cu_uu) {
+		this.cu_uu = cu_uu;
+	}
+
+	public Long getB2b_pd_id() {
+		return b2b_pd_id;
+	}
+
+	public void setB2b_pd_id(Long b2b_pd_id) {
+		this.b2b_pd_id = b2b_pd_id;
+	}
+
+	public Long getB2b_pr_id() {
+		return b2b_pr_id;
+	}
+
+	public void setB2b_pr_id(Long b2b_pr_id) {
+		this.b2b_pr_id = b2b_pr_id;
+	}
+
+	public String getSr_type() {
+		return sr_type;
+	}
+
+	public void setSr_type(String sr_type) {
+		this.sr_type = sr_type;
+	}
+
+	public SaleReply map() {
+		SaleReply.Builder builder = SaleReply.newBuilder();
+		builder.setSrId(sr_id);
+		if (null != sr_qty) {
+			builder.setSrQty(sr_qty);
+		}
+		if (null != sr_delivery) {
+			builder.setSrDelivery(sr_delivery.getTime());
+		}
+		if (!StringUtils.isEmpty(sr_remark)) {
+			builder.setSrRemark(sr_remark);
+		}
+		if (!StringUtils.isEmpty(sr_sacode)) {
+			builder.setSrSacode(sr_sacode);
+		}
+		builder.setSrSddetno(sr_sddetno);
+		if (null != sr_date) {
+			builder.setSrDate(sr_date.getTime());
+		}
+		if (!StringUtils.isEmpty(sr_recorder)) {
+			builder.setSrRecorder(sr_recorder);
+		}
+		builder.setCuUu(cu_uu);
+		if (null != b2b_pd_id) {
+			builder.setB2BPdId(b2b_pd_id);
+		}
+		if (null != b2b_pr_id) {
+			builder.setB2BPrId(b2b_pr_id);
+		}
+		if (!StringUtils.isEmpty(sr_type)) {
+			builder.setSrType(sr_type);
+		}
+		return builder.build();
+	}
+
+	@Override
+	public Object id() {
+		return sr_id;
+	}
+}

+ 51 - 0
uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/service/AbstractB2bService.java

@@ -0,0 +1,51 @@
+package com.usoftchina.uas.pl.b2b.service;
+
+import com.usoftchina.uas.pl.b2b.po.AttachPO;
+import com.usoftchina.uas.pl.service.AbstractService;
+import org.springframework.jdbc.core.BeanPropertyRowMapper;
+import org.springframework.util.CollectionUtils;
+import org.springframework.util.StringUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author yingp
+ * @date 2020/1/17
+ */
+public abstract class AbstractB2bService extends AbstractService {
+
+    /**
+     * 查找附件
+     *
+     * @param attachIds 附件ID
+     * @return
+     */
+    protected List<AttachPO> getAttachList(String[] attachIds) {
+        List<AttachPO> attaches = new ArrayList<AttachPO>();
+        if (attachIds.length > 0) {
+            String erpUrl = getEnterpriseErpUrl();
+            attaches = jdbcTemplate.query("select fp_id, fp_size, fp_name from filepath where fp_id in ("
+                    + String.join(",", attachIds) + ")", new BeanPropertyRowMapper<>(AttachPO.class));
+            if (!CollectionUtils.isEmpty(attaches)) {
+                for (AttachPO attach : attaches) {
+                    attach.setFp_url(erpUrl + AttachPO.DOWN_FILE_ACTION + attach.getFp_id());
+                }
+            }
+        }
+        return attaches;
+    }
+
+    /**
+     * 获取企业UAS外网地址
+     *
+     * @return
+     */
+    protected String getEnterpriseErpUrl() {
+        String erpUrl = queryForObject("select max(en_erpUrl) from enterprise", String.class);
+        if (!StringUtils.isEmpty(erpUrl) && erpUrl.endsWith("/")) {
+            erpUrl = erpUrl.substring(0, erpUrl.length() - 1);
+        }
+        return erpUrl;
+    }
+}

+ 67 - 0
uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/service/PurchaseBillService.java

@@ -0,0 +1,67 @@
+package com.usoftchina.uas.pl.b2b.service;
+
+import com.usoft.b2b.external.erp.invoice.api.entity.APBill;
+import com.usoftchina.uas.pl.b2b.po.PurchaseBillDetailPO;
+import com.usoftchina.uas.pl.b2b.po.PurchaseBillPO;
+import com.usoftchina.uas.pl.service.AbstractService;
+import org.springframework.dao.EmptyResultDataAccessException;
+import org.springframework.jdbc.core.BatchPreparedStatementSetter;
+import org.springframework.jdbc.core.BeanPropertyRowMapper;
+import org.springframework.stereotype.Service;
+
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.util.List;
+
+/**
+ * @author yingp
+ * @date 2020/1/15
+ */
+@Service
+public class PurchaseBillService extends AbstractService {
+
+    /**
+     * 待上传的应付发票
+     *
+     * @return
+     */
+    public List<PurchaseBillPO> toUploadBillList() {
+        try {
+            List<PurchaseBillPO> billList = jdbcTemplate.query(
+                    "select * from (select apbill.*, ve_uu ab_vendoruu from apbill"
+                            + " left join vendor on apbill.ab_vendcode = vendor.ve_code where ab_class = '应付发票' and ab_status = '已过账'"
+                            + " and ab_sendstatus = '待上传' and coalesce(ve_uu, '0') <> '0' and nvl(ab_kind,' ')<>'货款调账' and nvl(ve_b2benable,0)<>0 order by ab_id) where rownum <= 10",
+                    new BeanPropertyRowMapper<>(PurchaseBillPO.class));
+            billList.forEach(bill -> {
+                List<PurchaseBillDetailPO> detailList = jdbcTemplate.query(
+                        "select * from apbilldetail where abd_abid = ? order by abd_detno",
+                        new BeanPropertyRowMapper<>(PurchaseBillDetailPO.class), bill.getAb_id());
+                bill.setDetails(detailList);
+            });
+            return billList;
+        } catch (EmptyResultDataAccessException e) {
+            return null;
+        }
+    }
+
+    /**
+     * 标记应付发票已上传
+     *
+     * @param billList
+     */
+    public void setBillUploaded(final List<APBill> billList) {
+        jdbcTemplate.batchUpdate("update apbill set ab_sendStatus = '已上传', ab_b2bid = ? where ab_id = ?", new BatchPreparedStatementSetter() {
+            @Override
+            public void setValues(PreparedStatement ps, int i) throws SQLException {
+                APBill bill = billList.get(i);
+                ps.setObject(1, bill.getAbB2Bid());
+                ps.setObject(2, bill.getAbId());
+            }
+
+            @Override
+            public int getBatchSize() {
+                return billList.size();
+            }
+        });
+    }
+}

+ 77 - 0
uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/service/PurchaseChangeService.java

@@ -0,0 +1,77 @@
+package com.usoftchina.uas.pl.b2b.service;
+
+import com.usoft.b2b.external.erp.order.api.entity.PurchaseChangeReply;
+import com.usoftchina.uas.pl.b2b.agent.PurchaseChangeAgent;
+import com.usoftchina.uas.pl.b2b.po.PurchaseChangeDetailPO;
+import com.usoftchina.uas.pl.b2b.po.PurchaseChangePO;
+import com.usoftchina.uas.pl.service.AbstractService;
+import com.usoftchina.uas.pl.utils.Const;
+import com.usoftchina.uas.pl.utils.NumberUtils;
+import com.usoftchina.uas.pl.utils.Status;
+import com.usoftchina.uas.pl.utils.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.dao.EmptyResultDataAccessException;
+import org.springframework.jdbc.core.BeanPropertyRowMapper;
+import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author yingp
+ * @date 2020/1/13
+ */
+@Service
+public class PurchaseChangeService extends AbstractService {
+
+    @Autowired
+    private PurchaseChangeAgent purchaseChangeAgent;
+
+    /**
+     * 待上传到平台的采购变更单
+     *
+     * @return
+     */
+    public List<PurchaseChangePO> toUploadList() {
+        try {
+            List<PurchaseChangePO> purchaseChanges = jdbcTemplate.query("select purchasechange.* from purchasechange left join Purchase on pc_purccode=pu_code left join vendor on ve_code=pu_vendcode where PC_SENDSTATUS='待上传' and pu_sendstatus='已上传' and nvl(pu_ordertype,' ')<>'B2C' and nvl(pc_agreed,1)<>0 and pc_statuscode in ('AUDITED','TO_CONFIRM') and coalesce(ve_uu, '0') <> '0' and nvl(ve_b2benable,0)<>0 order by pc_code",
+                    new BeanPropertyRowMapper<>(PurchaseChangePO.class));
+            if (!CollectionUtils.isEmpty(purchaseChanges)) {
+                purchaseChanges.forEach(purchaseChange -> {
+                    List<PurchaseChangeDetailPO> changeDetails = jdbcTemplate.query(
+                            "select * from purchasechangedetail where pcd_pcid=?",
+                            new BeanPropertyRowMapper<>(PurchaseChangeDetailPO.class), purchaseChange.getPc_id());
+                    purchaseChange.setChangeDetails(changeDetails);
+                });
+            }
+            return purchaseChanges;
+        } catch (EmptyResultDataAccessException e) {
+            return null;
+        }
+    }
+
+    /**
+     * 保存平台回复记录,并更新到ERP采购单明细
+     *
+     * @param replyList
+     */
+    public void saveReplyList(List<PurchaseChangeReply> replyList) {
+        List<String> sqlList = new ArrayList<>();
+        replyList.forEach(reply -> {
+            sqlList.add("update purchasechange set pc_agreed=" + NumberUtils.nvl(reply.getPcAgreed(), 0) + ",pc_replyremark='"
+                    + StringUtils.nvl(reply.getPcReplyremark()) + "' where pc_code='" + reply.getPcCode() + "'");
+            boolean agreed = Const.YES == Math.abs(reply.getPcAgreed());
+            if (agreed) {
+                // 调用UAS接口执行同意动作
+                if (!purchaseChangeAgent.agree(reply.getPcCode())) {
+                    throw new RuntimeException("[调用UAS接口执行同意动作]出现异常");
+                }
+            } else {
+                sqlList.add("update purchasechange set pc_agreed=0,pc_status='" + Status.CONFIRMED.display() + "',pc_statuscode='"
+                        + Status.CONFIRMED.code() + "' where pc_code='" + reply.getPcCode() + "'");
+            }
+        });
+        jdbcTemplate.batchUpdate(sqlList.toArray(new String[]{}));
+    }
+}

+ 133 - 0
uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/service/PurchaseCheckService.java

@@ -0,0 +1,133 @@
+package com.usoftchina.uas.pl.b2b.service;
+
+import com.usoft.b2b.external.erp.reconciliation.api.entity.PurchaseApCheck;
+import com.usoftchina.uas.pl.b2b.po.SaleCheckDetailPO;
+import com.usoftchina.uas.pl.b2b.po.SaleCheckPO;
+import com.usoftchina.uas.pl.service.AbstractService;
+import com.usoftchina.uas.pl.utils.DateUtils;
+import com.usoftchina.uas.pl.utils.StringUtils;
+import org.springframework.dao.EmptyResultDataAccessException;
+import org.springframework.jdbc.core.BeanPropertyRowMapper;
+import org.springframework.stereotype.Service;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * @author yingp
+ * @date 2020/1/15
+ */
+@Service
+public class PurchaseCheckService extends AbstractService {
+
+    /**
+     * 保存saveSaleAPChecks
+     *
+     * @param checkList
+     */
+    public void saveCheckList(List<PurchaseApCheck> checkList) {
+        List<String> sqlList = new ArrayList<>();
+        StringBuffer idStr = new StringBuffer();
+        checkList.forEach(check -> {
+            int count = queryForObject("select count(1) from APCheck where ac_b2bid = ?",
+                    Integer.class, check.getAcB2Bid());
+            if (count == 0) {
+                int id = generate("APCheck_seq");
+                sqlList.add(toSaveSql(check, id));
+                if (check.getDetailsCount() > 0) {
+                    check.getDetailsList().forEach(detail -> {
+                        String orderClass = null;
+                        if ("货款调账".equals(detail.getAdOrderclass())) {
+                            orderClass = "APBILL";
+                        } else {
+                            orderClass = "PRODINOUT";
+                        }
+                        sqlList.add(toSaveDetailSql(detail, id, orderClass));
+                    });
+                }
+                if (idStr.length() > 0) {
+                    idStr.append(",");
+                }
+                idStr.append(id);
+            }
+        });
+        if (idStr.length() > 0) {
+            sqlList.add("update ApcheckDetail set (ad_pdid,ad_taxrate,ad_prodcode) = (select pd_id,pd_taxrate,pd_prodcode from prodinout left join prodiodetail on pi_id=pd_piid  "
+                    + " where pi_inoutno=ad_sourcecode and pd_pdno = ad_sourcedetno) where nvl(ad_sourcetype, ' ') = 'PRODINOUT' and ad_acid in ("
+                    + idStr.toString() + ")");
+            sqlList.add("update apcheck set (ac_vendcode,ac_vendname,ac_buyercode,ac_buyername,ac_paymentcode,ac_paymentname)=(select ve_code,ve_name,ve_buyercode,ve_buyername,ve_paymentcode,ve_payment from vendor where ac_venduu=ve_uu) where ac_id in ("
+                    + idStr.toString() + ")");
+            jdbcTemplate.batchUpdate(sqlList.toArray(new String[]{}));
+        }
+    }
+
+    public String toSaveSql(PurchaseApCheck check, int primaryKey) {
+        return "insert into ApCheck (ac_id,ac_b2bid,ac_fromdate,ac_todate ,ac_date,ac_recorder,ac_apdate,ac_remark,ac_checkamount,"
+                + "ac_currency,ac_rate,ac_paymentname,ac_code,ac_status,ac_statuscode,ac_venduu)"
+                + " values ( " + primaryKey
+                + ", "
+                + check.getAcB2Bid()
+                + ", "
+                + DateUtils.formatOracle(new Date(check.getAcFromdate()))
+                + ", "
+                + DateUtils.formatOracle(new Date(check.getAcTodate()))
+                + ", "
+                + DateUtils.formatOracle(new Date(check.getAcRecorddate()))
+                + ", '"
+                + StringUtils.nvl(check.getAcRecorder(), "")
+                + "', "
+                + DateUtils.formatOracle(new Date(check.getAcApdate()))
+                + ", '"
+                + check.getAcRemark()
+                + "', "
+                + check.getAcCheckamount()
+                + ", '"
+                + check.getAcCurrency()
+                + "', "
+                + check.getAcRate()
+                + ", '"
+                + check.getAcPaymentname()
+                + "', '"
+                + check.getAcCode()
+                + "'"
+                + ",'已审核','AUDITED','" + StringUtils.nvl(check.getAcEnuu(), "") + "')";
+    }
+
+    private String toSaveDetailSql(PurchaseApCheck.APCheckDetail detail, int primaryKey, String orderClass) {
+        return "insert into apcheckdetail(ad_id,ad_acid,ad_detno,ad_inoutno,ad_sourcecode,ad_sourcedetno,ad_sourcetype,ad_price,ad_b2bqty,ad_b2bamount)"
+                + " values ( " + "APCheckdetail_seq.nextval," + primaryKey + ", " + detail.getAdDetno() + ",'" + detail.getAdInoutno()
+                + "', '" + detail.getAdInoutno() + "', " + detail.getAdOrderdetno() + ",'" + orderClass + "', " + detail.getAdPrice() + ", " + detail.getAdB2Bqty()
+                + ", " + detail.getAdB2Bamount() + ")";
+    }
+
+    /**
+     * 上传ERP不同意/已确认的对账单
+     *
+     * @return
+     */
+    public List<SaleCheckPO> toUploadReplyList() {
+        try {
+            List<SaleCheckPO> checkList = jdbcTemplate.query("select apcheck.* from apcheck where ac_confirmstatus in ('已确认','不同意') and  ac_b2bid is not null and ac_sendstatus = '待上传'",
+                    new BeanPropertyRowMapper<>(SaleCheckPO.class));
+            checkList.forEach(check -> {
+                List<SaleCheckDetailPO> detailList = jdbcTemplate.query("select * from apcheckdetail where ad_acid = ?",
+                        new BeanPropertyRowMapper<>(SaleCheckDetailPO.class), check.getAc_id());
+                check.setDetails(detailList);
+            });
+            return checkList;
+        } catch (EmptyResultDataAccessException e) {
+            return null;
+        }
+    }
+
+    /**
+     * 标记不同意/已确认的对账单已上传平台
+     *
+     * @param checkList
+     */
+    public void setReplyListUploaded(List<SaleCheckPO> checkList) {
+        Map<String, Object> params = new HashMap<>(1);
+        params.put("ids", checkList.stream().map(check -> check.getAc_id()).distinct().collect(Collectors.toList()));
+        namedJdbcTemplate.update("update apcheck set ac_sendstatus='已上传' where ac_id in (:ids)", params);
+    }
+}

+ 95 - 0
uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/service/PurchaseInOutService.java

@@ -0,0 +1,95 @@
+package com.usoftchina.uas.pl.b2b.service;
+
+import com.usoft.b2b.external.erp.deliver.api.entity.PurchaseProdInOut;
+import com.usoftchina.uas.pl.b2b.po.PurchaseProdInOutDetailPO;
+import com.usoftchina.uas.pl.b2b.po.PurchaseProdInOutPO;
+import com.usoftchina.uas.pl.service.AbstractService;
+import org.springframework.dao.EmptyResultDataAccessException;
+import org.springframework.jdbc.core.BatchPreparedStatementSetter;
+import org.springframework.jdbc.core.BeanPropertyRowMapper;
+import org.springframework.stereotype.Service;
+
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * @author yingp
+ * @date 2020/1/14
+ */
+@Service
+public class PurchaseInOutService extends AbstractService {
+
+    /**
+     * 待上传的出入库单
+     *
+     * @param type 出入库类型
+     * @return
+     */
+    public List<PurchaseProdInOutPO> toUploadList(String type) {
+        try {
+            List<PurchaseProdInOutPO> inOutList = jdbcTemplate.query(
+                    "select * from (select prodinout.*, ve_uu pi_vendoruu from prodinout left join vendor on prodinout.pi_cardcode = vendor.ve_code where pi_class=? and pi_status = '已过账' and (pi_sendstatus = '待上传' or pi_sendstatus='上传中') and coalesce(ve_uu, '0') <> '0' and nvl(ve_b2benable,0)<>0 ) where rownum <= 20 and exists (select 1 from prodiodetail left join purchase on pd_ordercode=pu_code where pd_piid=pi_id and (pd_ordercode is null or pu_sendstatus='已上传'))",
+                    new BeanPropertyRowMapper<>(PurchaseProdInOutPO.class), type);
+            inOutList.forEach(inOut -> {
+                List<PurchaseProdInOutDetailPO> details = jdbcTemplate.query(
+                        "select prodiodetail.* , pd_pdno pd_detno from prodiodetail where pd_piid = ? ",
+                        new BeanPropertyRowMapper<>(PurchaseProdInOutDetailPO.class), inOut.getPi_id());
+                inOut.setDetails(details);
+            });
+            return inOutList;
+        } catch (EmptyResultDataAccessException e) {
+            return null;
+        }
+    }
+
+    /**
+     * 更新出入库单的上传状态
+     *
+     * @param inOutList
+     */
+    public void setUploaded(final List<PurchaseProdInOut> inOutList) {
+        jdbcTemplate.batchUpdate("update prodInout set pi_sendStatus = '已上传', pi_b2b_id = ? where pi_id = ?", new BatchPreparedStatementSetter() {
+            @Override
+            public void setValues(PreparedStatement ps, int i) throws SQLException {
+                PurchaseProdInOut inOut = inOutList.get(i);
+                ps.setObject(1, inOut.getPiB2BId());
+                ps.setObject(2, inOut.getPiId());
+            }
+
+            @Override
+            public int getBatchSize() {
+                return inOutList.size();
+            }
+        });
+    }
+
+    /**
+     * 更新出入库单的上传状态
+     *
+     * @param inOutList
+     */
+    public void setUploaded2(final List<PurchaseProdInOutPO> inOutList) {
+        Map<String, Object> params = new HashMap<>(1);
+        params.put("ids", inOutList.stream().map(inOut -> inOut.getPi_id()).distinct().collect(Collectors.toList()));
+        namedJdbcTemplate.update("update prodInout set pi_sendStatus = '已上传' where pi_id in (:ids)", params);
+    }
+
+    /**
+     * 待上传反过账的出入库单
+     *
+     * @param type 出入库类型
+     * @return
+     */
+    public List<PurchaseProdInOutPO> toUploadUnList(String type) {
+        try {
+            return jdbcTemplate.query("select * from (select pi_id , pi_inoutno from prodinout where pi_class=? and pi_status='未过账' and pi_sendstatus='上传中') where rownum<=500",
+                    new BeanPropertyRowMapper<>(PurchaseProdInOutPO.class), type);
+        } catch (EmptyResultDataAccessException e) {
+            return null;
+        }
+    }
+}

+ 306 - 0
uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/service/PurchaseNotifyService.java

@@ -0,0 +1,306 @@
+package com.usoftchina.uas.pl.b2b.service;
+
+import com.alibaba.fastjson.JSON;
+import com.usoft.b2b.external.erp.deliver.api.entity.AcceptNotify;
+import com.usoft.b2b.external.erp.deliver.api.entity.PurchaseNotify;
+import com.usoftchina.uas.pl.b2b.po.*;
+import com.usoftchina.uas.pl.service.AbstractService;
+import com.usoftchina.uas.pl.utils.DateUtils;
+import com.usoftchina.uas.pl.utils.Status;
+import com.usoftchina.uas.pl.utils.StringUtils;
+import org.springframework.dao.EmptyResultDataAccessException;
+import org.springframework.jdbc.core.BatchPreparedStatementSetter;
+import org.springframework.jdbc.core.BeanPropertyRowMapper;
+import org.springframework.stereotype.Service;
+
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * @author yingp
+ * @date 2020/1/14
+ */
+@Service
+public class PurchaseNotifyService extends AbstractService {
+
+    /**
+     * 待上传平台送货提醒
+     *
+     * @return
+     */
+    public List<PurchaseNotifyPO> toUploadPurchaseNotifyList() {
+        try {
+            return jdbcTemplate.query("select * from (select purchasenotify.*,ve_uu,pr_zxbzs from purchasenotify left join purchase on pn_ordercode=pu_code left join vendor on pu_vendcode=ve_code left join product on pr_code=pn_prodcode where nvl(PN_SENDSTATUS,' ')='待上传'and pn_status<>'已取消' and nvl(pu_sendstatus, '') = '已上传' and nvl(pu_ordertype,' ')<>'B2C' and coalesce(ve_uu, '0') <> '0' and nvl(ve_b2benable,0)<>0 order by pn_indate) where rownum <= 100",
+                    new BeanPropertyRowMapper<>(PurchaseNotifyPO.class));
+        } catch (EmptyResultDataAccessException e) {
+            return null;
+        }
+    }
+
+    /**
+     * 标记为已上传平台
+     *
+     * @param notifyList
+     */
+    public void setPurchaseNotifyUploaded(final List<PurchaseNotify> notifyList) {
+        jdbcTemplate.batchUpdate("update purchaseNotify set pn_sendStatus = '已上传', pn_b2bid = ? where pn_id = ?", new BatchPreparedStatementSetter() {
+            @Override
+            public void setValues(PreparedStatement ps, int i) throws SQLException {
+                PurchaseNotify notify = notifyList.get(i);
+                ps.setObject(1, notify.getPnB2Bid());
+                ps.setObject(2, notify.getPnId());
+            }
+
+            @Override
+            public int getBatchSize() {
+                return notifyList.size();
+            }
+        });
+    }
+
+    /**
+     * 保存从平台下载的收料通知
+     *
+     * @param acceptList
+     * @return AcceptNotify.an_id
+     */
+    public Set<Integer> saveAcceptNotifyList(List<AcceptNotify> acceptList) {
+        List<String> sqlList = new ArrayList<>();
+        Set<Integer> anIdSet = new HashSet<>();
+        Set<Long> pnIdSet = new HashSet<>();
+        acceptList.forEach(accept -> {
+            int count = queryForObject("select count(1) from AcceptNotify where b2b_ss_id=?", Integer.class, accept.getB2BSsId());
+            if (count == 0) {
+                int anId = generate("AcceptNotify_seq");
+                anIdSet.add(anId);
+                String anCode = generateCode("AcceptNotify", 2);
+                sqlList.add(toSaveSql(accept, anId, anCode));
+                if (accept.getDetailsCount() > 0) {
+                    accept.getDetailsList().forEach(detail -> {
+                        sqlList.add(toSaveDetailSql(detail, anId));
+                        pnIdSet.add(detail.getAndPnid());
+                    });
+                } else {
+                    throw new IllegalArgumentException("发货单 " + accept.getAnSendcode() + " 没有明细");
+                }
+            }
+        });
+        if (!anIdSet.isEmpty()) {
+            String anIdStr = StringUtils.collectionToCommaDelimitedString(anIdSet);
+            sqlList.add("update AcceptNotify set (an_currency,an_rate,an_paymentcode,an_payment,an_buyer,an_buyerid)=(select pu_currency,pu_rate,pu_paymentscode,pu_payments,pu_buyername,em_id from purchase left join acceptnotifydetail on pu_code=and_ordercode left join employee on pu_buyercode=em_code where and_anid=an_id and rownum=1) where an_id in ("
+                    + anIdStr + ")");
+            sqlList.add("update AcceptNotify set (an_vendcode,an_vendname)=(select pu_vendcode,pu_vendname from purchase left join acceptnotifydetail on pu_code=and_ordercode where and_anid=an_id and rownum=1) where an_id in ("
+                    + anIdStr + ") and an_vendcode is null");
+            sqlList.add("update AcceptNotifyDetail set (and_orderid,and_prodcode,and_taxrate)=(select pd_id,pd_prodcode,nvl(pd_rate,0) from purchasedetail left join purchase on pd_puid=pu_id where pu_code=and_ordercode and pd_detno=and_orderdetno) where and_anid in ("
+                    + anIdStr + ")");
+
+            String pnIdStr = StringUtils.collectionToCommaDelimitedString(pnIdSet);
+            sqlList.add("update purchasenotify set pn_endqty=(select sum(and_inqty) from AcceptNotifyDetail where and_pnid=pn_id) where pn_id in ("
+                    + pnIdStr + ")");
+            sqlList.add("update purchasenotify set pn_status='部分发货' where nvl(pn_endqty,0)>0 and nvl(pn_endqty,0)<nvl(pn_qty,0) and pn_id in ("
+                    + pnIdStr + ") and nvl(pn_status, '') <> '已取消'");
+            sqlList.add("update purchasenotify set pn_status='已发货' where nvl(pn_endqty,0)=nvl(pn_qty,0) and pn_id in ("
+                    + pnIdStr + ") and nvl(pn_status, '') <> '已取消'");
+
+            jdbcTemplate.batchUpdate(sqlList.toArray(new String[]{}));
+        }
+        return anIdSet;
+    }
+
+    private String toSaveSql(AcceptNotify accept, int primaryKey, String code) {
+        return "insert into AcceptNotify(b2b_ss_id,an_id,an_code,an_venduu,an_buyeruu,an_sendcode,an_status,an_statuscode,an_date,an_indate,an_sendstatus,an_recorder) values ("
+                + accept.getB2BSsId()
+                + ","
+                + primaryKey
+                + ",'"
+                + code
+                + "',"
+                + accept.getAnVenduu()
+                + ","
+                + accept.getAnBuyeruu()
+                + ",'"
+                + accept.getAnSendcode()
+                + "','"
+                + Status.AUDITED.display()
+                + "','"
+                + Status.AUDITED.code()
+                + "',sysdate,sysdate,'已下载','"
+                + StringUtils.nvl(accept.getAnRecorder(), "")
+                + "')";
+    }
+
+    public String toSaveDetailSql(AcceptNotify.AcceptNotifyDetail detail, int foreignKey) {
+        return "insert into AcceptNotifyDetail(and_id,and_anid,and_detno,and_ordercode,and_orderdetno,and_inqty,and_b2bqty,and_remark,and_price,and_pnid) values (AcceptNotifyDetail_seq.nextval,"
+                + foreignKey
+                + ","
+                + detail.getAndDetno()
+                + ",'"
+                + detail.getAndOrdercode()
+                + "',"
+                + detail.getAndOrderdetno()
+                + ","
+                + detail.getAndInqty()
+                + ","
+                + detail.getAndInqty()
+                + ",'"
+                + StringUtils.nvl(detail.getAndRemark(), "") + "',"
+                + detail.getAndPrice() + ","
+                + detail.getAndPnid() + ")";
+    }
+
+    /**
+     * 待上传到平台的主动维护的收料通知
+     *
+     * @return
+     */
+    public List<AcceptNotifyPO> toUploadAcceptNotifyList() {
+        try {
+            List<AcceptNotifyPO> acceptList = jdbcTemplate.query("select AcceptNotify.* from AcceptNotify left join vendor on an_vendcode=ve_code where AN_SENDSTATUS='待上传' and an_statuscode='AUDITED' and coalesce(ve_uu, '0') <> '0' and nvl(ve_b2benable,0)<>0 and B2B_SS_ID is not null order by an_date",
+                    new BeanPropertyRowMapper<>(AcceptNotifyPO.class));
+            acceptList.forEach(accept -> {
+                List<AcceptNotifyDetailPO> details = jdbcTemplate.query("select * from AcceptNotifyDetail where and_anid=?",
+                        new BeanPropertyRowMapper<>(AcceptNotifyDetailPO.class), accept.getAn_id());
+                accept.setDetails(details);
+            });
+            return acceptList;
+        } catch (EmptyResultDataAccessException e) {
+            return null;
+        }
+    }
+
+    /**
+     * 标记本地的收料通知已经上传到平台
+     *
+     * @param acceptList
+     */
+    public void setAcceptNotifyUploaded(final List<AcceptNotify> acceptList) {
+        jdbcTemplate.batchUpdate("update AcceptNotify set an_sendstatus='已下载', b2b_ss_id = ? where an_id = ?", new BatchPreparedStatementSetter() {
+            @Override
+            public void setValues(PreparedStatement ps, int i) throws SQLException {
+                AcceptNotify acceptNotify = acceptList.get(i);
+                ps.setObject(1, acceptNotify.getB2BSsId());
+                ps.setObject(2, acceptNotify.getAnId());
+            }
+
+            @Override
+            public int getBatchSize() {
+                return acceptList.size();
+            }
+        });
+    }
+
+    /**
+     * 待上传平台已结案送货提醒
+     *
+     * @return
+     */
+    public List<PurchaseNotifyPO> toUploadPurchaseNotifyEndList() {
+        try {
+            return jdbcTemplate.query("select * from (select purchasenotify.pn_id,ve_uu from purchasenotify left join purchase on pn_ordercode=pu_code left join vendor on pu_vendcode=ve_code where PN_SENDSTATUS='待上传' and pn_statuscode='CANCELED' and pu_sendstatus='已上传' and nvl(pu_ordertype,' ')<>'B2C' and pn_b2bid is not null and coalesce(ve_uu, '0') <> '0' and nvl(ve_b2benable,0)<>0 order by pn_indate) where rownum<=400",
+                    new BeanPropertyRowMapper<>(PurchaseNotifyPO.class));
+        } catch (EmptyResultDataAccessException e) {
+            return null;
+        }
+    }
+
+    /**
+     * 标记已结案送货提醒已上传到平台
+     *
+     * @param pnIdArray
+     */
+    public void setPurchaseNotifyEndUploaded(String[] pnIdArray) {
+        Map<String, Object> params = new HashMap<>(1);
+        params.put("ids", Arrays.asList(pnIdArray));
+        namedJdbcTemplate.update("update PurchaseNotify set PN_SENDSTATUS='已上传' where pn_id in (:ids)", params);
+    }
+
+    /**
+     * 待上传平台的收料通知确认数
+     *
+     * @return
+     */
+    public List<AcceptNotifyConfirmPO> toUploadConfirmList() {
+        try {
+            return jdbcTemplate.query("select b2b_ss_id,and_id,and_detno,and_inqty from AcceptNotify left join vendor on an_vendcode=ve_code left join AcceptNotifyDetail on and_anid=an_id where b2b_ss_id is not null and an_statuscode in ('AUDITED','TURNVA', 'PART2VA') and and_sendstatus='待上传' and and_inqty<nvl(and_b2bqty,and_inqty) and coalesce(ve_uu, '0') <> '0' and nvl(ve_b2benable,0)<>0 order by b2b_ss_id,and_detno",
+                    new BeanPropertyRowMapper<>(AcceptNotifyConfirmPO.class));
+        } catch (EmptyResultDataAccessException e) {
+            return null;
+        }
+    }
+
+    /**
+     * 标记收料通知确认数已上传到平台
+     *
+     * @param confirmList
+     */
+    public void setConfirmListUploaded(List<AcceptNotifyConfirmPO> confirmList) {
+        Map<String, Object> params = new HashMap<>(1);
+        params.put("ids", confirmList.stream().map(confirm -> confirm.getAnd_id()).distinct().collect(Collectors.toList()));
+        namedJdbcTemplate.update("update AcceptNotifyDetail set and_sendstatus='已下载',and_b2bqty=and_inqty where and_id in (:ids)", params);
+        // 更新主记录的收料状态
+        namedJdbcTemplate.update("update AcceptNotify set an_statuscode='TURNVA',an_status='"
+                        + Status.TURNVA.display()
+                        + "' where exists (select 1 from AcceptNotifydetail where and_id in (:ids) and and_anid=an_id) and not exists (select 1 from AcceptNotifydetail where and_anid=an_id and and_inqty>NVL(and_yqty,0))",
+                params);
+    }
+
+    /**
+     * 待上传平台的收料单收料数
+     *
+     * @return
+     */
+    public List<AcceptNotifyVerifyPO> toUploadVerifyList() {
+        try {
+            return jdbcTemplate.query("select vad_id, acceptnotify.b2b_ss_id, ACCEPTNOTIFYDETAIL.and_detno, ve_code, vad_jyqty, ve_okqty, ve_notokqty,ve_testman, ve_date from VERIFYAPPLYDETAIL left join VERIFYAPPLY on vad_vaid = va_id left join ACCEPTNOTIFYDETAIL on vad_andid=and_id  left join acceptnotify on and_anid=an_id where VERIFYAPPLYDETAIL.ve_status='已审核' and VERIFYAPPLYDETAIL.vad_sendstatus='待上传' and acceptnotify.b2b_ss_id is not null and rownum <= 200",
+                    new BeanPropertyRowMapper<>(AcceptNotifyVerifyPO.class));
+        } catch (EmptyResultDataAccessException e) {
+            return null;
+        }
+    }
+
+    /**
+     * 待上传平台的收料单取消收料数
+     *
+     * @return
+     */
+    public List<AcceptNotifyVerifyPO> toUploadUnVerifyList() {
+        try {
+            return jdbcTemplate.query("select vad_id, acceptnotify.b2b_ss_id, ACCEPTNOTIFYDETAIL.and_detno from VERIFYAPPLYDETAIL left join VERIFYAPPLY on vad_vaid = va_id left join ACCEPTNOTIFYDETAIL on vad_andid=and_id left join acceptnotify on and_anid=an_id where VERIFYAPPLYDETAIL.ve_status<>'已审核' and VERIFYAPPLYDETAIL.vad_sendstatus='上传中' and acceptnotify.b2b_ss_id is not null and rownum <= 50",
+                    new BeanPropertyRowMapper<>(AcceptNotifyVerifyPO.class));
+        } catch (EmptyResultDataAccessException e) {
+            return null;
+        }
+    }
+
+    /**
+     * 标记(审核/反审核)收料单收料数已上传平台
+     *
+     * @param verifyList
+     */
+    public void setVerifyListUploaded(List<AcceptNotifyVerifyPO> verifyList) {
+        Map<String, Object> params = new HashMap<>(1);
+        params.put("ids", verifyList.stream().map(verify -> verify.getVad_id()).distinct().collect(Collectors.toList()));
+        namedJdbcTemplate.update("update verifyapplydetail set vad_sendstatus='已上传' where vad_id in (:ids)", params);
+    }
+
+    /**
+     * 最近1小时的结案送货提醒
+     *
+     * @return
+     */
+    public List<PurchaseNotifyPO> lastHourPurchaseNotifyEndList() {
+        try {
+            String nowDay = DateUtils.format(new Date());
+            Date startTime = Date.from(LocalDateTime.now().plusHours(-1).atZone(ZoneId.systemDefault()).toInstant());
+            Date endTime = Date.from(LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant());
+            return jdbcTemplate.query("select pn_id,pn_b2bid,pn_cmdRemark pn_remark from purchaseNotify where pn_b2bid is not null and pn_cmdRemark like ? and to_date(subStr(pn_cmdRemark, -20), 'yyyy-MM-dd hh24:mi:ss') between ? and ?",
+                    new BeanPropertyRowMapper<>(PurchaseNotifyPO.class), "%勾选取消  " + nowDay + "%", startTime, endTime);
+        } catch (EmptyResultDataAccessException e) {
+            return null;
+        }
+    }
+}

+ 189 - 0
uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/service/PurchaseService.java

@@ -0,0 +1,189 @@
+package com.usoftchina.uas.pl.b2b.service;
+
+import com.usoft.b2b.external.erp.order.api.entity.MessageLog;
+import com.usoft.b2b.external.erp.order.api.entity.Purchase;
+import com.usoft.b2b.external.erp.order.api.entity.PurchaseReply;
+import com.usoftchina.uas.pl.b2b.po.PurchaseDetailEndPO;
+import com.usoftchina.uas.pl.b2b.po.PurchaseDetailPO;
+import com.usoftchina.uas.pl.b2b.po.PurchasePO;
+import com.usoftchina.uas.pl.b2b.po.PurchaseReplyPO;
+import com.usoftchina.uas.pl.utils.Const;
+import com.usoftchina.uas.pl.utils.DateUtils;
+import com.usoftchina.uas.pl.utils.StringUtils;
+import org.springframework.dao.EmptyResultDataAccessException;
+import org.springframework.jdbc.core.BatchPreparedStatementSetter;
+import org.springframework.jdbc.core.BeanPropertyRowMapper;
+import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * @author yingp
+ * @date 2020/1/13
+ */
+@Service
+public class PurchaseService extends AbstractB2bService {
+
+    /**
+     * 获取需要上传平台的采购单
+     *
+     * @return
+     */
+    public List<PurchasePO> toUploadList() {
+        try {
+            List<PurchasePO> purchases = jdbcTemplate.query("select * from (select purchase.*,em_uu,em_name,em_sex,em_mobile,em_email,vendor.ve_uu,pu_vendcontact ve_contact,purchase.pu_vendcontactuu ve_contactuu from purchase left join vendor on pu_vendcode=ve_code left join employee on pu_buyerid=em_id where (PU_SENDSTATUS='待上传' or PU_SENDSTATUS='上传中') and pu_statuscode='AUDITED' and nvl(pu_ordertype,' ')<>'B2C' and coalesce(ve_uu, '0') <> '0' and nvl(ve_b2benable,0)<>0 and not exists (select 1 from purchasedetail,product where pd_puid=pu_id and pr_code=pd_prodcode and pr_sendstatus<>'已上传') order by pu_code) where rownum < 100",
+                    new BeanPropertyRowMapper<>(PurchasePO.class));
+            List<PurchasePO> thisPost = new ArrayList<>();
+            if (!CollectionUtils.isEmpty(purchases)) {
+                int count = 0;
+                for (PurchasePO purchase : purchases) {
+                    List<PurchaseDetailPO> purchaseDetails = jdbcTemplate.query("select * from (select p.*,product.pr_oldcode ,product.pr_oldname,product.pr_oldspec,(select max(pv_vendprodspec) from productvendor where pv_prodcode=pd_prodcode and pv_vendcode=?) as pd_vendspec from purchasedetail p left join product on pr_code=pd_prodcode where pd_puid=?)",
+                            new BeanPropertyRowMapper<>(PurchaseDetailPO.class), purchase.getPu_vendcode(), purchase.getPu_id());
+                    if (!CollectionUtils.isEmpty(purchaseDetails)) {
+                        for (PurchaseDetailPO detail : purchaseDetails) {
+                            if (StringUtils.hasText(detail.getPd_prattach())) {
+                                detail.setAttaches(getAttachList(detail.getPd_prattach().split(";")));
+                            }
+                        }
+                    }
+                    purchase.setPurchaseDetails(purchaseDetails);
+                    thisPost.add(purchase);
+                    if ((count = count + purchaseDetails.size()) >= Const.DATA_SIZE_LIMIT) {
+                        break;
+                    }
+                }
+            }
+            return thisPost;
+        } catch (EmptyResultDataAccessException e) {
+            return null;
+        }
+    }
+
+    /**
+     * 标记为已上传平台
+     *
+     * @param purchaseList
+     */
+    public void setUploaded(final List<Purchase> purchaseList) {
+        jdbcTemplate.batchUpdate("update purchase set pu_sendStatus = '已上传', pu_b2bid = ? where pu_id = ?", new BatchPreparedStatementSetter() {
+            @Override
+            public void setValues(PreparedStatement ps, int i) throws SQLException {
+                Purchase purchase = purchaseList.get(i);
+                ps.setObject(1, purchase.getPuB2Bid());
+                ps.setObject(2, purchase.getPuId());
+            }
+
+            @Override
+            public int getBatchSize() {
+                return purchaseList.size();
+            }
+        });
+    }
+
+    /**
+     * 保存平台回复
+     *
+     * @param replyList
+     */
+    public void saveReplyList(List<PurchaseReply> replyList) {
+        List<String> sqlList = new ArrayList<String>();
+        replyList.forEach(reply -> {
+            sqlList.add("update PurchaseReply set pr_ifoverdate=-1 where pr_pucode='" + reply.getPrPucode() + "' and pr_pddetno=" +
+                    reply.getPrPddetno() + " and nvl(pr_ifoverdate,0)<>-1");
+            // 接口调整,reply.pr_qty表示最新的回复数量
+            // PurchaseDetail.pd_deliveryReply是varchar2类型
+            sqlList.add("update PurchaseDetail set pd_qtyreply=" + reply.getPrQty()
+                    + ", pd_deliveryReply = '" + DateUtils.format(new Date(reply.getPrDelivery())) + "', pd_replydetail='"
+                    + StringUtils.nvl(reply.getPrRemark(), "") + "',pd_vendoreplydate="
+                    + DateUtils.formatOracle(new Date()) + " where pd_code='" + reply.getPrPucode()
+                    + "' and pd_detno=" + reply.getPrPddetno());
+            sqlList.add("MERGE into PurchaseReply a using (select count(1) c from PurchaseReply where b2b_pr_id="
+                    + reply.getB2BPrId()
+                    + ") b on (b.c>0) when NOT MATCHED THEN insert (b2b_pr_id,pr_id,pr_qty,pr_delivery,pr_remark,pr_pucode,pr_pddetno,pr_date,pr_recorder,pr_type,pr_sendstatus) values ("
+                    + reply.getB2BPrId() + ",PURCHASEREPLY_SEQ.nextval," + +reply.getPrQty() + ","
+                    + DateUtils.formatOracle(new Date(reply.getPrDelivery())) + ",'" + StringUtils.nvl(reply.getPrRemark(), "")
+                    + "','" + reply.getPrPucode() + "'," + reply.getPrPddetno() + ","
+                    + DateUtils.formatOracle(new Date(reply.getPrDate())) + ",'" + reply.getPrRecorder() + "','"
+                    + StringUtils.nvl(reply.getPrType(), "") + "','已下载')");
+        });
+        jdbcTemplate.batchUpdate(sqlList.toArray(new String[]{}));
+    }
+
+    /**
+     * 结案采购订单,上传平台
+     *
+     * @return
+     */
+    public List<PurchaseDetailEndPO> toUploadEndList() {
+        try {
+            return jdbcTemplate.query("select * from (select pd_id,pd_code,pd_detno,case when pd_mrpstatuscode='FINISH' then 1 else 0 end pd_ended from PurchaseDetail left join purchase on pd_puid=pu_id left join vendor on pu_vendcode=ve_code where PU_SENDSTATUS='已上传' and nvl(pu_ordertype,' ')<>'B2C' and pd_endstatus='待上传' and coalesce(ve_uu, '0') <> '0' and nvl(ve_b2benable,0)<>0 order by pd_code,pd_detno) where rownum <= 200",
+                    new BeanPropertyRowMapper<>(PurchaseDetailEndPO.class));
+        } catch (EmptyResultDataAccessException e) {
+            return null;
+        }
+    }
+
+    /**
+     * 设置结案采购订单已上传平台
+     *
+     * @param detailEndList
+     */
+    public void setEndUploaded(final List<PurchaseDetailEndPO> detailEndList) {
+        List<Integer> idList = detailEndList.stream().map(end -> end.getPd_id()).distinct().collect(Collectors.toList());
+        Map<String, Object> params = new HashMap<>(1);
+        params.put("ids", idList);
+        namedJdbcTemplate.update("update purchasedetail set PD_ENDSTATUS='已上传' where pd_id in (:ids)", params);
+    }
+
+    /**
+     * 保存平台打印日志
+     *
+     * @param logList
+     */
+    public void savePrintLogList(List<MessageLog> logList) {
+        List<String> sqlList = new ArrayList<String>();
+        logList.forEach(log -> {
+            sqlList.add("insert into MessageLog values("
+                    + "messagelog_seq.nextval," + DateUtils.formatOracle(new Date(log.getMlDate())) + ",'"
+                    + log.getMlMan() + "','"
+                    + log.getMlContent() + "','"
+                    + log.getMlResult() + "','"
+                    + log.getMlSearch() + "','"
+                    + log.getCode() + "')");
+            String search = log.getMlSearch();
+            String[] where = search.split("\\|");
+            sqlList.add("update purchase set pu_printstatus = '已打印' where " + where[1]);
+        });
+        jdbcTemplate.batchUpdate(sqlList.toArray(new String[]{}));
+    }
+
+    /**
+     * 获取需要上传平台的采购单本地回复
+     *
+     * @return
+     */
+    public List<PurchaseReplyPO> toUploadReplyList() {
+        try {
+            return jdbcTemplate.query("select * from (select pr_id,pr_qty,pr_delivery,pr_remark,pr_pucode,pr_pddetno,pr_date,pr_recorder,b2b_pr_id,pr_type from PurchaseReply left join PurchaseDetail on pr_pucode=pd_code and pr_pddetno=pd_detno left join purchase on pd_puid=pu_id left join vendor on pu_vendcode=ve_code where PR_SENDSTATUS='待上传' and coalesce(ve_uu, '0') <> '0' and nvl(ve_b2benable,0)<>0 and nvl(b2b_pr_id,0)=0 order by pr_date) where rownum <= 10",
+                    new BeanPropertyRowMapper<>(PurchaseReplyPO.class));
+        } catch (EmptyResultDataAccessException e) {
+            return null;
+        }
+    }
+
+    /**
+     * 标记本地回复已上传到平台
+     *
+     * @param replyList
+     */
+    public void setReplyUploaded(final List<PurchaseReplyPO> replyList) {
+        List<Integer> idList = replyList.stream().map(reply -> reply.getPr_id()).distinct().collect(Collectors.toList());
+        Map<String, Object> params = new HashMap<>(1);
+        params.put("ids", idList);
+        namedJdbcTemplate.update("update PurchaseReply set pr_sendstatus='已下载' where pr_id in (:ids)", params);
+    }
+}

+ 154 - 0
uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/service/SaleBillService.java

@@ -0,0 +1,154 @@
+package com.usoftchina.uas.pl.b2b.service;
+
+import com.usoft.b2b.external.erp.invoice.api.entity.APBill;
+import com.usoft.b2b.external.erp.invoice.api.entity.APBillDetail;
+import com.usoftchina.uas.pl.utils.DateUtils;
+import com.usoftchina.uas.pl.utils.StringUtils;
+import com.usoftchina.uas.pl.service.AbstractService;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * @author yingp
+ * @date 2020/1/15
+ */
+@Service
+public class SaleBillService extends AbstractService {
+
+    /**
+     * 保存saledownchange
+     *
+     * @param billList
+     */
+    public void saveBillList(List<APBill> billList) {
+        List<String> sqlList = new ArrayList<>();
+        StringBuffer idStr = new StringBuffer();
+        billList.forEach(bill -> {
+            int count = queryForObject("select count(1) from apbilldown where ab_b2bid = ?",
+                    Integer.class, bill.getAbB2Bid());
+            if (count == 0) {
+                int id = generate("apbilldown_seq");
+                sqlList.add(toSaveSql(bill, id));
+                if (bill.getDetailsCount() > 0) {
+                    bill.getDetailsList().forEach(detail -> {
+                        sqlList.add(toSaveDetailSql(detail, id));
+                    });
+                }
+                if (idStr.length() > 0) {
+                    idStr.append(",");
+                }
+                idStr.append(id);
+            }
+        });
+        if (idStr.length() > 0) {
+            sqlList.add("update apbilldown set (ab_custcode,ab_custname)=(select cu_code,cu_name from customer where cu_uu=ab_customeruu) where ab_id in (" +
+                    idStr.toString() + ")");
+            sqlList.add("update apbilldowndetail set (abd_prodcode) = (select pc_prodcode from productcustomer "
+                    + "where pc_custprodcode = apbilldowndetail.abd_custprodcode and "
+                    + "pc_custproddetail = apbilldowndetail.abd_custproddetail and "
+                    + "pc_custprodspec = apbilldowndetail.abd_custprodspec)  where abd_abid in (" + idStr.toString() + ")");
+            jdbcTemplate.batchUpdate(sqlList.toArray(new String[]{}));
+        }
+    }
+
+    public String toSaveSql(APBill bill, int primaryKey) {
+        return "insert into apbilldown (ab_id, ab_b2bid, ab_code, ab_date, ab_yearmonth, ab_currency, ab_rate,"
+                + " ab_buyer, ab_customeruu, ab_status, ab_payments, ab_paydate, ab_refno, ab_recorder, "
+                + "ab_indate, ab_apamount, ab_payamount, ab_pricetermdes, ab_taxsum, ab_differ, ab_remark)"
+                + " values ( " + primaryKey
+                + ", "
+                + bill.getAbB2Bid()
+                + ", '"
+                + bill.getAbCode()
+                + "', "
+                + DateUtils.formatOracle(new Date(bill.getAbDate()))
+                + ", '"
+                + DateUtils.format(new Date(bill.getAbYearmonth()), "yyyyMM")
+                + "', '"
+                + StringUtils.nvl(bill.getAbCurrency(), "")
+                + "', "
+                + bill.getAbRate()
+                + ", '"
+                + StringUtils.nvl(bill.getAbBuyer(), "")
+                + "', "
+                + bill.getAbCustomeruu()
+                + ", '"
+                + bill.getAbStatus()
+                + "', '"
+                + StringUtils.nvl(bill.getAbPayments(), "")
+                + "', "
+                + DateUtils.formatOracle(new Date(bill.getAbPaydate()))
+                + ", '"
+                + StringUtils.nvl(bill.getAbRefno(), "")
+                + "', '"
+                + StringUtils.nvl(bill.getAbRecorder(), "")
+                + "', "
+                + DateUtils.formatOracle(new Date(bill.getAbIndate()))
+                + ", "
+                + bill.getAbApamount()
+                + ", "
+                + bill.getAbPayamount()
+                + ", '"
+                + StringUtils.nvl(bill.getAbPricetermdes(), "")
+                + "', "
+                + bill.getAbTaxsum()
+                + ", "
+                + bill.getAbDiffer()
+                + ", '"
+                + StringUtils.nvl(bill.getAbRemark(), "")
+                + "'"
+                + ")";
+    }
+
+    public String toSaveDetailSql(APBillDetail detail, int foreignKey) {
+        return "insert into apbilldowndetail (abd_id, abd_abid, abd_detno, abd_ordercode, abd_orderdetno, abd_pdinoutno"
+                + ", abd_thisvoqty, abd_price, abd_taxrate, abd_amount, abd_totalbillprice, abd_qty, abd_thisvoprice"
+                + ", abd_apamount, abd_noapamount, abd_taxamount, abd_remark, abd_invoqty, abd_yqty, abd_custprodcode, abd_custproddetail, abd_custprodspec)"
+                + " values ( apbilldowndetail_seq.nextval, " + foreignKey
+                + ", "
+                + detail.getAbdDetno()
+                + ", '"
+                + StringUtils.nvl(detail.getAbdOrdercode(), "")
+                + "', "
+                + detail.getAbdOrderdetno()
+                + ", '"
+                + StringUtils.nvl(detail.getAbdPdinoutno(), "")
+                + "', "
+                + detail.getAbdThisvoqty()
+                + ", "
+                + detail.getAbdPrice()
+                + ", "
+                + detail.getAbdTaxrate()
+                + ", "
+                + detail.getAbdAmount()
+                + ", "
+                + detail.getAbdTotalbillprice()
+                + ", "
+                + detail.getAbdQty()
+                + ", "
+                + detail.getAbdThisvoprice()
+                + ", "
+                + detail.getAbdApamount()
+                + ", "
+                + detail.getAbdNoapamount()
+                + ", "
+                + detail.getAbdTaxamount()
+                + ", '"
+                + StringUtils.nvl(detail.getAbdRemark(), "")
+                + "', "
+                + detail.getAbdInvoqty()
+                + ", "
+                + detail.getAbdYqty()
+                + ", '"
+                + StringUtils.nvl(detail.getAbdCustprodcode(), "")
+                + "', '"
+                + StringUtils.nvl(detail.getAbdCustproddetail(), "")
+                + "', '"
+                + StringUtils.nvl(detail.getAbdCustprodspec(), "")
+                + "'"
+                + ")";
+    }
+}

+ 199 - 0
uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/service/SaleChangeService.java

@@ -0,0 +1,199 @@
+package com.usoftchina.uas.pl.b2b.service;
+
+import com.usoft.b2b.external.erp.order.api.entity.SaleDownChange;
+import com.usoft.b2b.external.erp.order.api.entity.SaleDownChangeReply;
+import com.usoftchina.uas.pl.b2b.po.SaleDownChangeReplyPO;
+import com.usoftchina.uas.pl.service.AbstractService;
+import com.usoftchina.uas.pl.utils.*;
+import org.springframework.dao.EmptyResultDataAccessException;
+import org.springframework.jdbc.core.BeanPropertyRowMapper;
+import org.springframework.stereotype.Service;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * @author yingp
+ * @date 2020/1/13
+ */
+@Service
+public class SaleChangeService extends AbstractService {
+
+    /**
+     * 保存saledownchange
+     *
+     * @param changeList
+     */
+    public void saveSaleDownChange(List<SaleDownChange> changeList) {
+        List<String> sqlList = new ArrayList<>();
+        StringBuffer idStr = new StringBuffer();
+        changeList.forEach(change -> {
+            int count = queryForObject("select count(1) from SaleDownChange where sc_type='purchase' and b2b_pc_id=?",
+                    Integer.class, change.getB2BPcId());
+            if (count == 0) {
+                int scId = generate("SaleDownChange_SEQ");
+                sqlList.add(toSaveSql(change, scId));
+                if (change.getChangeDetailsCount() > 0) {
+                    change.getChangeDetailsList().forEach(detail -> {
+                        sqlList.add(toSaveDetailSql(detail, scId));
+                    });
+                }
+                if (idStr.length() > 0) {
+                    idStr.append(",");
+                }
+                idStr.append(scId);
+                // 无需回复
+                if (Const.YES == change.getScUnNeedReply()) {
+                    sqlList.add("update saledownchange set sc_agreed= -1 , sc_replyremark='无需回复',sc_status='" + Status.AUDITED.display()
+                            + "',sc_statuscode='" + Status.AUDITED.code() + "',sc_sendstatus='已下载' where sc_id=" + scId);
+                    // 变更达成
+                    sqlList.add("update SaleDown set (sa_payments,sa_currency,sa_rate)=(select max(nvl(sc_newpayments,sc_payments)),max(nvl(sc_currency,sc_newcurrency)),max(nvl(sc_rate,sc_newrate)) from SaleDownChange where sc_sacode=sa_code and sc_id=" + scId +
+                            ") where sa_code=(select sc_sacode from SaleDownChange where sc_id=" + scId + ")");
+                    sqlList.add("update SaleDownDetail set (sd_custprodcode,sd_custproddetail,sd_custprodspec,sd_custprodunit,sd_prodcode)=(select max(scd_newcustprodcode),max(scd_newcustproddetail),max(scd_newcustprodspec),max(scd_newcustprodunit),max(scd_newprodcode) from SaleDownChangeDetail where scd_sacode=sd_code and scd_sddetno=sd_detno and scd_scid=" + scId +
+                            ") where exists (select 1 from SaleDownChangeDetail where scd_scid=" + scId +
+                            " and scd_sacode=sd_code and scd_sddetno=sd_detno and nvl(scd_newprodcode,scd_prodcode)<>scd_prodcode)");
+                    sqlList.add("update SaleDownDetail set (sd_delivery,sd_qty,sd_price,sd_taxrate)=(select max(nvl(scd_newdelivery,scd_delivery)),max(nvl(scd_newqty,scd_qty)),max(nvl(scd_newprice,scd_price)),max(nvl(scd_newtaxrate,scd_taxrate)) from SaleDownChangeDetail where scd_scid=" + scId +
+                            " and scd_sacode=sd_code and scd_sddetno=sd_detno) where exists (select 1 from SaleDownChangeDetail where scd_scid=" + scId + " and scd_sacode=sd_code and scd_sddetno=sd_detno)");
+                }
+            }
+        });
+        if (idStr.length() > 0) {
+            sqlList.add("update SaleDownChange set (sc_custcode,sc_paymentscode,sc_payments,sc_currency,sc_rate)=(select max(sa_custcode),max(sa_paymentscode),max(sa_payments),max(sa_currency),max(sa_rate) from saledown where sa_code=sc_sacode) where sc_id in ("
+                    + idStr.toString() + ")");
+            sqlList.add("update SaleDownChangeDetail sd1 set scd_newprodcode=(select max(pc_prodcode) from productcustomer,saledownchange,saledownchangedetail sd2 where sc_id=scd_scid and pc_custcode=sc_custcode and pc_custprodcode=sd2.scd_newcustprodcode and pc_custproddetail=sd2.scd_newcustproddetail and pc_custprodspec=sd2.scd_newcustprodspec and sd1.scd_id=sd2.scd_id) where scd_scid in ("
+                    + idStr.toString() + ")");
+            sqlList.add("update SaleDownChangeDetail set scd_sacode=(select sc_sacode from SaleDownChange where sc_id=scd_scid) where scd_scid in ("
+                    + idStr.toString() + ")");
+            sqlList.add("update SaleDownChangeDetail set (scd_prodcode,scd_custprodcode,scd_qty,scd_price,scd_taxrate,scd_delivery)=(select max(sd_prodcode),max(sd_custprodcode),max(sd_qty),max(sd_price),max(sd_taxrate),max(sd_delivery) from saledowndetail left join saledown on sd_said=sa_id where sa_code=scd_sacode and sd_detno=scd_sddetno) where scd_scid in ("
+                    + idStr.toString() + ")");
+            jdbcTemplate.batchUpdate(sqlList.toArray(new String[]{}));
+        }
+    }
+
+    /**
+     * 新增saleDownChange
+     *
+     * @param change
+     * @param primaryKey
+     * @return
+     */
+    public String toSaveSql(SaleDownChange change, int primaryKey) {
+        boolean agreed = Const.YES == Math.abs(change.getScAgreed());
+        return "insert into SaleDownChange(sc_id,b2b_pc_id,sc_code,sc_sacode,sc_custuu,sc_indate,sc_recorder,sc_newpayments,sc_newcurrency,sc_newrate,sc_description,sc_remark,sc_status,sc_statuscode,sc_agreed,sc_replyremark,sc_sendstatus,sc_type) values ("
+                + primaryKey
+                + ","
+                + change.getB2BPcId()
+                + ",'"
+                + change.getScCode()
+                + "','"
+                + change.getScSacode()
+                + "',"
+                + change.getScCustuu()
+                + ","
+                + DateUtils.formatOracle(new Date(change.getScIndate()))
+                + ",'"
+                + change.getScRecorder()
+                + "','"
+                + StringUtils.nvl(change.getScNewpayments(), "")
+                + "','"
+                + StringUtils.nvl(change.getScNewcurrency(), "")
+                + "',"
+                + NumberUtils.nvl(change.getScNewrate(), 1)
+                + ",'"
+                + StringUtils.nvl(change.getScDescription(), "")
+                + "','"
+                + StringUtils.nvl(change.getScRemark(), "")
+                + "','"
+                + Status.ENTERING.display()
+                + "','"
+                + Status.ENTERING.code()
+                + "',"
+                + (agreed ? 1 : "null")
+                + ",'"
+                + (agreed ? "客户已确认变更" : "")
+                + "','"
+                + (agreed ? "已下载" : "")
+                + "','purchase')";
+    }
+
+    public String toSaveDetailSql(SaleDownChange.SaleDownChangeDetail detail, int foreignKey) {
+        return "insert into SaleDownChangeDetail(scd_id,scd_scid,scd_detno,scd_sddetno,scd_newcustprodcode,scd_newcustproddetail,scd_newcustprodspec,scd_newcustprodunit,scd_newqty,scd_newprice,scd_newtaxrate,scd_newdelivery,scd_remark) values (SaleDownChangeDetail_SEQ.nextval,"
+                + foreignKey
+                + ","
+                + detail.getScdDetno()
+                + ","
+                + detail.getScdSddetno()
+                + ",'"
+                + StringUtils.nvl(detail.getScdNewcustprodcode(), "")
+                + "','"
+                + StringUtils.nvl(detail.getScdNewcustproddetail(), "")
+                + "','"
+                + StringUtils.nvl(detail.getScdNewcustprodspec(), "")
+                + "','"
+                + StringUtils.nvl(detail.getScdNewcustprodunit(), "")
+                + "',"
+                + NumberUtils.nvl(detail.getScdNewqty(), 0)
+                + ","
+                + NumberUtils.nvl(detail.getScdNewprice(), 0)
+                + ","
+                + NumberUtils.nvl(detail.getScdNewtaxrate(), 0)
+                + ","
+                + DateUtils.formatOracle(new Date(detail.getScdNewdelivery()))
+                + ",'"
+                + StringUtils.nvl(detail.getScdRemark(), "") + "')";
+    }
+
+    /**
+     * 从平台下载的回复信息,更新到客户采购变更单里面
+     */
+    public void saveDownloadedReplyList(List<SaleDownChangeReply> replyList) {
+        List<String> sqlList = new ArrayList<String>();
+        replyList.forEach(reply -> {
+            Integer sc_id = queryForObject("select sc_id from saledownchange where sc_code=? and sc_statuscode<>'AUDITED'",
+                    Integer.class, reply.getScCode());
+            if (null != sc_id) {
+                sqlList.add("update saledownchange set sc_agreed=" + -1 * Math.abs(NumberUtils.nvl(reply.getScAgreed(), 0)) + ",sc_replyremark='"
+                        + StringUtils.nvl(reply.getScReplyremark(), "") + "',sc_status='" + Status.AUDITED.display()
+                        + "',sc_statuscode='" + Status.AUDITED.code() + "',sc_sendstatus='已下载' where sc_id=" + sc_id);
+                boolean agreed = Const.YES == Math.abs(reply.getScAgreed());
+                if (agreed) {
+                    // 变更达成
+                    sqlList.add("update SaleDown set (sa_payments,sa_currency,sa_rate)=(select max(nvl(sc_newpayments,sc_payments)),max(nvl(sc_currency,sc_newcurrency)),max(nvl(sc_rate,sc_newrate)) from SaleDownChange where sc_sacode=sa_code and sc_id=" + sc_id +
+                            ") where sa_code=(select sc_sacode from SaleDownChange where sc_id=" + sc_id + ")");
+                    sqlList.add("update SaleDownDetail set (sd_custprodcode,sd_custproddetail,sd_custprodspec,sd_custprodunit,sd_prodcode)=(select max(scd_newcustprodcode),max(scd_newcustproddetail),max(scd_newcustprodspec),max(scd_newcustprodunit),max(scd_newprodcode) from SaleDownChangeDetail where scd_sacode=sd_code and scd_sddetno=sd_detno and scd_scid=" + sc_id +
+                            ") where exists (select 1 from SaleDownChangeDetail where scd_scid=" + sc_id +
+                            " and scd_sacode=sd_code and scd_sddetno=sd_detno and nvl(scd_newprodcode,scd_prodcode)<>scd_prodcode)");
+                    sqlList.add("update SaleDownDetail set (sd_delivery,sd_qty,sd_price,sd_taxrate)=(select max(nvl(scd_newdelivery,scd_delivery)),max(nvl(scd_newqty,scd_qty)),max(nvl(scd_newprice,scd_price)),max(nvl(scd_newtaxrate,scd_taxrate)) from SaleDownChangeDetail where scd_scid=" + sc_id +
+                            " and scd_sacode=sd_code and scd_sddetno=sd_detno) where exists (select 1 from SaleDownChangeDetail where scd_scid=" + sc_id + " and scd_sacode=sd_code and scd_sddetno=sd_detno)");
+                }
+            }
+        });
+        jdbcTemplate.batchUpdate(sqlList.toArray(new String[]{}));
+    }
+
+    /**
+     * 待上传平台的变更回复
+     *
+     * @return
+     */
+    public List<SaleDownChangeReplyPO> toUploadReplyList() {
+        try {
+            return jdbcTemplate.query("select b2b_pc_id,sc_id,sc_code,sc_agreed,sc_replyremark from SaleDownChange where SC_SENDSTATUS='待上传' and sc_agreed is not null and sc_custuu is not null",
+                    new BeanPropertyRowMapper<>(SaleDownChangeReplyPO.class));
+        } catch (EmptyResultDataAccessException e) {
+            return null;
+        }
+    }
+
+    /**
+     * 上传本地变更回复信息到平台后,更新状态
+     *
+     * @param replyList
+     */
+    public void saveUploadedReplyList(List<SaleDownChangeReply> replyList) {
+        String[] codes = replyList.stream().map(reply -> reply.getScCode()).collect(Collectors.toSet()).toArray(new String[]{});
+        Map<String, Object> params = new HashMap<>(1);
+        params.put("codes", codes);
+        namedJdbcTemplate.update("update SaleDownChange set sc_sendstatus='已下载' where sc_code in (:codes)", params);
+    }
+}

+ 149 - 0
uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/service/SaleNotifyService.java

@@ -0,0 +1,149 @@
+package com.usoftchina.uas.pl.b2b.service;
+
+import com.usoft.b2b.external.erp.deliver.api.entity.SaleNotifyDown;
+import com.usoft.b2b.external.erp.deliver.api.entity.SaleNotifyDownEnd;
+import com.usoft.b2b.external.erp.deliver.api.entity.SaleOut;
+import com.usoftchina.uas.pl.b2b.po.SaleOutDetailPO;
+import com.usoftchina.uas.pl.b2b.po.SaleOutPO;
+import com.usoftchina.uas.pl.service.AbstractService;
+import com.usoftchina.uas.pl.utils.DateUtils;
+import com.usoftchina.uas.pl.utils.NumberUtils;
+import com.usoftchina.uas.pl.utils.Status;
+import com.usoftchina.uas.pl.utils.StringUtils;
+import org.springframework.jdbc.core.BeanPropertyRowMapper;
+import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * @author yingp
+ * @date 2020/1/14
+ */
+@Service
+public class SaleNotifyService extends AbstractService {
+
+    /**
+     * 保存saleNotifyDown
+     *
+     * @param notifyList
+     */
+    public void saveSaleNotifyDownList(List<SaleNotifyDown> notifyList) {
+        List<String> sqlList = new ArrayList<>();
+        StringBuffer idStr = new StringBuffer();
+        notifyList.forEach(notify -> {
+            int count = queryForObject("select count(1) from SaleNotifyDown where b2b_pn_id=?",
+                    Integer.class, notify.getB2BPnId());
+            if (count == 0) {
+                int snId = generate("SaleNotifyDown_SEQ");
+                sqlList.add(toSaveSql(notify, snId));
+                if (idStr.length() > 0) {
+                    idStr.append(",");
+                }
+                idStr.append(snId);
+            } else {
+                // 修改送货提醒的交期和数量
+                sqlList.add("update SaleNotifyDown set sn_delivery="
+                        + DateUtils.formatOracle(new Date(notify.getSnDelivery()))
+                        + ", sn_qty=" + notify.getSnQty() + " where b2b_pn_id=" + notify.getB2BPnId());
+            }
+        });
+        if (idStr.length() > 0) {
+            sqlList.add("update SaleNotifyDown set (sn_custcode,sn_custname)=(select cu_code,cu_name from customer where cu_uu=sn_custuu) where sn_id in ("
+                    + idStr.toString() + ")");
+            sqlList.add("update SaleNotifyDown sn set (SN_CUSTPRODCODE,SN_CUSTPRODDETAIL,SN_CUSTPRODSPEC)=(select sd.SD_CUSTPRODCODE,sd.SD_CUSTPRODDETAIL,sd.SD_CUSTPRODSPEC from SaleDownDetail sd left join SaleDown on sa_id=sd_said where sa_code=sn.sn_pocode and sd_detno=sn.sn_podetno) where sn_id in ("
+                    + idStr.toString() + ")");
+            sqlList.add("update SaleNotifyDown set (sn_ordercode,sn_orderdetno,sn_orderqty,sn_prodcode)=(select sale.sa_code,saledetail.sd_detno,saledetail.sd_qty,saledowndetail.sd_prodcode from saledowndetail left join saledown on saledowndetail.sd_said=saledown.sa_id left join saledetail on saledetail.sd_sourceid=saledowndetail.sd_id left join sale on sale.sa_id=saledetail.sd_said and sale.sa_sourcetype in ('CUSTPO','B2B商务') and sale.sa_pocode=saledown.sa_code where saledown.sa_code=SaleNotifyDown.sn_pocode and saledowndetail.sd_detno=SaleNotifyDown.sn_podetno) where sn_id in ("
+                    + idStr.toString() + ") and sn_pocode is not null and sn_podetno is not null");
+        }
+        jdbcTemplate.batchUpdate(sqlList.toArray(new String[]{}));
+    }
+
+    private String toSaveSql(SaleNotifyDown notify, int primaryKey) {
+        return "insert into SaleNotifyDown(b2b_pn_id,sn_id,sn_custuu,sn_pocode,sn_podetno,sn_remark,sn_qty,sn_delivery,sn_sendqty) values ("
+                + notify.getB2BPnId() + "," + primaryKey + "," + notify.getSnCustuu() + ",'" + notify.getSnPocode() + "'," + notify.getSnPodetno() + ",'"
+                + StringUtils.nvl(notify.getSnRemark(), "") + "'," + notify.getSnQty() + ","
+                + DateUtils.formatOracle(new Date(notify.getSnDelivery())) + ","
+                + NumberUtils.nvl(notify.getSnSendqty(), 0) + ")";
+    }
+
+    /**
+     * 根据平台做的发货单,修改客户送货提醒的发货数
+     *
+     * @param outList
+     */
+    public void saveSaleOutList(List<SaleOut> outList) {
+        List<Object[]> args = new ArrayList<>();
+        outList.forEach(out -> {
+            if (out.getDetailsCount() > 0) {
+                out.getDetailsList().forEach(detail -> {
+                    args.add(new Object[]{detail.getPdOutqty(), detail.getB2BPnId()});
+                });
+            }
+        });
+        jdbcTemplate.batchUpdate("update salenotifydown set sn_sendqty=nvl(sn_sendqty,0) + ? where b2b_pn_id=?", args);
+    }
+
+    /**
+     * 待上传到平台的发货单
+     *
+     * @return
+     */
+    public List<SaleOutPO> toUploadSaleOutList() {
+        List<SaleOutPO> outList = jdbcTemplate.query("select pi_id,pi_inoutno,pi_currency,pi_rate,pi_payment,pi_remark,pi_recordman,pi_auditman,cu_uu from ProdInOut left join customer on pi_cardcode=cu_code where pi_class='出货单' and pi_statuscode='POSTED' and (PI_SENDSTATUS='待上传' or PI_SENDSTATUS='上传中') and cu_uu is not null and exists (select 1 from ProdIoDetail left join sale on pd_ordercode=sa_code where pd_piid=pi_id and sa_sourcetype in ('CUSTPO','B2B商务')) order by pi_inoutno",
+                new BeanPropertyRowMapper<>(SaleOutPO.class));
+        if (!CollectionUtils.isEmpty(outList)) {
+            List<SaleOutPO> validList = new ArrayList<>(outList.size());
+            outList.forEach(out -> {
+                List<SaleOutDetailPO> detailList = jdbcTemplate.query(
+                        // 客户送货提醒单转的出货单
+                        "select pd_pdno,pd_sendprice,pd_outqty,pd_ordercode,pd_orderdetno,b2b_pn_id,pd_noticeid,null pd_orderid from prodiodetail left join SaleNotifyDown on pd_noticeid=sn_id where pd_piid=? and nvl(pd_noticeid,0)<>0" +
+                                // 客户送货提醒单转的通知单,通知单转的出货单
+                                " UNION ALL select pd_pdno,pd_sendprice,pd_outqty,pd_ordercode,pd_orderdetno,b2b_pn_id,snd_noticeid pd_noticeid,null pd_orderid from prodiodetail left join SendNotifyDetail on pd_orderid=snd_id left join SaleNotifyDown on snd_noticeid=sn_id where pd_piid=? and nvl(pd_snid,0)<>0 and nvl(pd_noticeid,0)=0 and nvl(snd_noticeid,0)<>0" +
+                                // 客户采购单转的销售订单,直接转出货单,无关联的送货提醒
+                                " UNION ALL select pd_pdno,pd_sendprice,pd_outqty,pd_ordercode,pd_orderdetno,null b2b_pn_id,null pd_noticeid,sdd.b2b_pd_id pd_orderid from prodiodetail left join SaleDetail sd on pd_ordercode=sd.sd_code and pd_orderdetno=sd.sd_detno left join SaleDownDetail sdd on sd.sd_sourceid=sdd.sd_id where pd_piid=? and nvl(pd_snid,0)=0 and nvl(pd_noticeid,0)=0" +
+                                // 客户采购单转的销售订单,直接转通知单,然后转出货单,无关联的送货提醒
+                                " UNION ALL select pd_pdno,pd_sendprice,pd_outqty,pd_ordercode,pd_orderdetno,null b2b_pn_id,null pd_noticeid,sdd.b2b_pd_id pd_orderid from prodiodetail left join SendNotifyDetail on pd_orderid=snd_id left join SaleDetail sd on pd_ordercode=sd.sd_code and pd_orderdetno=sd.sd_detno left join SaleDownDetail sdd on sd.sd_sourceid=sdd.sd_id where pd_piid=? and nvl(pd_snid,0)<>0 and nvl(pd_noticeid,0)=0 and nvl(snd_noticeid,0)=0",
+                        new BeanPropertyRowMapper<>(SaleOutDetailPO.class), out.getPi_id(), out.getPi_id(), out.getPi_id(), out.getPi_id());
+                if (!CollectionUtils.isEmpty(detailList)) {
+                    out.setDetails(detailList);
+                    validList.add(out);
+                }
+            });
+            return validList;
+        }
+        return null;
+    }
+
+    /**
+     * 发货单上传平台后,修改客户送货提醒的发货数
+     *
+     * @param outList
+     */
+    public void setSaleOutUploaded(List<SaleOutPO> outList) {
+        List<Object[]> args = new ArrayList<>();
+        outList.forEach(out -> {
+            out.getDetails().forEach(detail -> {
+                args.add(new Object[]{detail.getPd_outqty(), detail.getPd_noticeid()});
+            });
+        });
+        jdbcTemplate.batchUpdate("update salenotifydown set sn_sendqty=nvl(sn_sendqty,0) + ? where sn_id=?", args);
+
+        Map<String, Object> params = new HashMap<>(1);
+        params.put("ids", outList.stream().map(out -> out.getPi_id()).distinct().collect(Collectors.toList()));
+        namedJdbcTemplate.update("update ProdInOut set pi_sendstatus='已上传' where pi_id in (:ids)", params);
+    }
+
+    /**
+     * 结案、反结案客户送货提醒单
+     *
+     * @param endList
+     */
+    public void saveNotifyDownEndList(final List<SaleNotifyDownEnd> endList) {
+        Map<String, Object> params = new HashMap<>(1);
+        params.put("ids", endList.stream().map(end -> end.getB2BPnId()).distinct().collect(Collectors.toList()));
+        namedJdbcTemplate.update("update SaleNotifyDown set sn_status='" + Status.FINISH.display() + "',sn_statuscode='" + Status.FINISH.code()
+                + "' where b2b_pn_id in (:ids)", params);
+    }
+}

+ 267 - 0
uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/service/SaleService.java

@@ -0,0 +1,267 @@
+package com.usoftchina.uas.pl.b2b.service;
+
+import com.usoft.b2b.external.erp.order.api.entity.SaleDown;
+import com.usoft.b2b.external.erp.order.api.entity.SaleDownDetailEnd;
+import com.usoft.b2b.external.erp.order.api.entity.SaleReply;
+import com.usoftchina.uas.pl.b2b.po.SaleReplyPO;
+import com.usoftchina.uas.pl.service.AbstractService;
+import com.usoftchina.uas.pl.utils.*;
+import org.springframework.dao.EmptyResultDataAccessException;
+import org.springframework.jdbc.core.BatchPreparedStatementSetter;
+import org.springframework.jdbc.core.BeanPropertyRowMapper;
+import org.springframework.stereotype.Service;
+
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * @author yingp
+ * @date 2020/1/13
+ */
+@Service
+public class SaleService extends AbstractService {
+
+    /**
+     * 保存从平台下载的saledown
+     *
+     * @param sales
+     */
+    public void saveSaleDown(List<SaleDown> sales) {
+        List<String> sqls = new ArrayList<>();
+        StringBuffer idStr = new StringBuffer();
+        List<Long> idList = new ArrayList<Long>();
+        sales.forEach(sale -> {
+            int count = queryForObject("select count(1) from SaleDown where sa_type='purchase' and b2b_pu_id=?", Integer.class, sale.getB2BPuId());
+            if (count == 0) {
+                int saId = generate("SaleDown_SEQ");
+                Float rate = sale.getSaRate();
+                String rateStr = queryForObject("select cm_crrate from currencysmonth left join Currencys on cr_name=cm_crname where cm_yearmonth = ? and cm_crname = ? and nvl(cr_statuscode,' ')='CANUSE'",
+                        String.class, DateUtils.format(new Date(sale.getSaDate()), "yyyyMM"), sale.getSaCurrency());
+                if (!StringUtils.isEmpty(rateStr)) {
+                    rate = Float.parseFloat(rateStr);
+                }
+                sqls.add(toSaveSql(sale, saId, rate));
+                idList.add(Long.valueOf(saId));
+                if (sale.getSaleDownDetailsCount() > 0) {
+                    sale.getSaleDownDetailsList().forEach(detail -> {
+                        sqls.add(toSaveDetailSql(detail, saId));
+                    });
+                }
+                // 这里先查询当前的客户UU号对应的客户资料是否存在,客户资料存在才进行后续的更新操作
+                int custCount = queryForObject("select count(1) from customer where cu_uu = ?", Integer.class, sale.getSaCustomeruu());
+                if (custCount > 0) {
+                    if (idStr.length() > 0) {
+                        idStr.append(",");
+                    }
+                    idStr.append(saId);
+                }
+            }
+        });
+        if (idStr.length() > 0) {
+            sqls.add("update SaleDown set (sa_custid,sa_custcode,sa_custname,sa_apcustcode,sa_apcustname,sa_shcustcode,sa_shcustname,sa_sellerid,sa_seller,sa_sellercode)=(select cu_id,cu_code,cu_name,cu_arcode,cu_arname,cu_shcustcode,cu_shcustname,cu_sellerid,cu_sellername,em_code from customer left join employee on em_id=cu_sellerid where cu_uu=sa_customeruu) where sa_id in ("
+                    + idStr.toString() + ")");
+            sqls.add("merge into SaleDownDetail d " +
+                    "using (select distinct pc_prodid,pc_prodcode,pc_custproddetail,pc_custprodspec,pc_custprodcode,pc_custcode from saledown " +
+                    "inner join productcustomer on pc_custcode = sa_custcode and sa_id in (" + idStr.toString() + ")) p " +
+                    "on (d.sd_custprodcode = p.pc_custprodcode and sd_said in (" + idStr.toString() + ")" +
+                    " and not exists(select count(1) from productcustomer t where t.pc_custcode=p.pc_custcode and t.pc_custprodcode= D.sd_custprodcode group by pc_custcode,pc_custprodcode HAVING count(1) > 1)) " +
+                    "when matched then " +
+                    "update set d.sd_prodid = p.pc_prodid,d.sd_prodcode = p.pc_prodcode,d.sd_custproddetail = p.pc_custproddetail,d.sd_prodcustcode = p.pc_custprodspec");
+            // 更新客户采购订单明细中的物料,客户物料编号与我司编码一致的料号
+            sqls.add("merge into SaleDownDetail d " +
+                    "using product p on (d.sd_custprodcode = p.pr_code and d.sd_said in (" + idStr.toString() + ")) " +
+                    "when matched then " +
+                    "update set sd_prodid = p.pr_id, sd_prodcode = p.pr_code");
+        }
+        if (sqls.size() > 0) {
+            jdbcTemplate.batchUpdate(sqls.toArray(new String[]{}));
+        }
+    }
+
+    private String toSaveSql(SaleDown saleDown, int sa_id, Float rate) {
+        return "insert into SaleDown(b2b_pu_id, sa_type, sa_id, sa_code, sa_pocode, sa_customeruu, sa_custname, sa_date, sa_recorddate, sa_payments, sa_currency, sa_rate, sa_shipby, sa_selleruu, sa_custcontact,sa_custcontactuu,sa_custmobile,sa_remark) VALUES ("
+                + saleDown.getB2BPuId()
+                + ", '"
+                + "purchase"
+                + "',"
+                + sa_id
+                + ",'"
+                + saleDown.getSaCode()
+                + "','"
+                + saleDown.getSaPocode()
+                + "',"
+                + saleDown.getSaCustomeruu()
+                + ", '"
+                + saleDown.getSaCustname()
+                + "',"
+                + DateUtils.formatOracle(new Date(saleDown.getSaDate()))
+                + ","
+                + DateUtils.formatOracle(new Date(saleDown.getSaRecorddate()))
+                + ",'"
+                + StringUtils.nvl(saleDown.getSaPayments(), "")
+                + "','"
+                + saleDown.getSaCurrency()
+                + "',"
+                + NumberUtils.nvl(rate, 1)
+                + ",'"
+                + StringUtils.nvl(saleDown.getSaShipby(), "")
+                + "',"
+                + saleDown.getSaUseruu()
+                + ",'"
+                + StringUtils.nvl(saleDown.getSaCustcontact(), "")
+                + "',"
+                + saleDown.getSaCustcontactuu()
+                + ",'" + StringUtils.nvl(saleDown.getSaCustmobile(), "")
+                + "','"
+                + saleDown.getSaRemark()
+                + "')";
+    }
+
+    public String toSaveDetailSql(SaleDown.SaleDownDetail detail, int sa_id) {
+        return "insert into SaleDownDetail(b2b_pd_id,sd_id,sd_said,sd_code,sd_detno,sd_custprodcode,sd_custproddetail,sd_prodname,sd_custprodspec,sd_prodspec,"
+                + "sd_custprodunit,sd_replyqty,sd_replydate,sd_replydetail,sd_price,sd_qty,sd_total,sd_taxrate,sd_SpecPrice,sd_SpecTaxRate,sd_SpecCurrency,"
+                + "sd_taxtotal,sd_delivery,sd_remark,sd_purcvendname,sd_purcvenduu,sd_purcdetno,sd_acceptcustname,sd_acceptcustaddress,sd_purcvendcode,sd_prodtaxcode,"
+                + "sd_prodbillname,sd_prodorispeccode) VALUES ("
+                + detail.getB2BPdId()
+                + ",SaleDownDetail_SEQ.nextval,"
+                + sa_id
+                + ",'"
+                + detail.getSdCode()
+                + "',"
+                + detail.getSdDetno()
+                + ",'"
+                + detail.getSdCustprodcode()
+                + "','"
+                + StringUtils.nvl(detail.getSdCustproddetail(), "")
+                + "','"
+                + StringUtils.nvl(detail.getSdCustproddetail(), "")
+                + "','"
+                + StringUtils.nvl(detail.getSdCustprodspec(), "")
+                + "','"
+                + StringUtils.nvl(detail.getSdCustprodspec(), "")
+                + "','"
+                + StringUtils.nvl(detail.getSdCustprodunit(), "")
+                + "',"
+                + NumberUtils.nvl(detail.getSdReplyqty(), 0)
+                + ","
+                + DateUtils.formatOracle(new Date(detail.getSdReplydate()))
+                + ",'"
+                + StringUtils.nvl(detail.getSdReplydetail(), "")
+                + "',"
+                + NumberUtils.nvl(detail.getSdPrice(), 0)
+                + ","
+                + NumberUtils.nvl(detail.getSdQty(), 0)
+                + ","
+                + NumberUtils.nvl(detail.getSdTotal(), 0)
+                + ","
+                + NumberUtils.nvl(detail.getSdTaxrate(), 0)
+                + ","
+                + NumberUtils.nvl(detail.getSdSpecPrice(), 0)
+                + ","
+                + NumberUtils.nvl(detail.getSdSpecTaxRate(), 0)
+                + ",'"
+                + StringUtils.nvl(detail.getSdSpecCurrency(), "")
+                + "',"
+                + NumberUtils.nvl(detail.getSdTaxtotal(), 0)
+                + ","
+                + DateUtils.formatOracle(new Date(detail.getSdDelivery()))
+                + ",'"
+                + detail.getSdRemark()
+                + "','"
+                + detail.getSdPurcvendname()
+                + "',"
+                + detail.getSdPurcvenduu()
+                + ","
+                + detail.getSdPurcdetno()
+                + ",'"
+                + StringUtils.nvl(detail.getSdAcceptcustname(), "")
+                + "','"
+                + StringUtils.nvl(detail.getSdAcceptcustaddress(), "")
+                + "',(select ve_code from vendor where ve_uu=" + detail.getSdPurcvenduu() + " and rownum=1)"
+                + ",'"
+                + StringUtils.nvl(detail.getSdProdtaxcode(), "")
+                + "','"
+                + StringUtils.nvl(detail.getSdProdbillname(), "")
+                + "','"
+                + StringUtils.nvl(detail.getSdProdorispeccode(), "")
+                + "')";
+    }
+
+    /**
+     * 保存从平台下载的回复记录
+     *
+     * @param replyList
+     */
+    public void saveReplyList(List<SaleReply> replyList) {
+        List<String> sqlList = new ArrayList<String>();
+        replyList.forEach(reply -> {
+            sqlList.add("MERGE into SaleDownDetail a using (select count(1) c from SaleReply where b2b_pr_id=" + reply.getB2BPrId()
+                    + ") b on (b.c=0) when MATCHED THEN update set sd_replyqty = nvl(sd_replyqty, 0) + " + reply.getSrQty()
+                    + ", sd_replydate = " + DateUtils.formatOracle(new Date(reply.getSrDelivery())) + ", sd_replydetail='"
+                    + StringUtils.nvl(reply.getSrRemark(), "") + "' where b2b_pd_id=" + reply.getB2BPdId() + " and sd_code='"
+                    + reply.getSrSacode() + "' and sd_detno=" + reply.getSrSddetno());
+            sqlList.add("MERGE into SaleReply a using (select count(1) c from SaleReply where b2b_pr_id="
+                    + reply.getB2BPrId()
+                    + ") b on (b.c>0) when NOT MATCHED THEN insert (b2b_pr_id,sr_qty,sr_delivery,sr_remark,sr_sacode,sr_sddetno,sr_date,sr_recorder,sr_type,sr_sendstatus) values ("
+                    + reply.getB2BPrId() + "," + +reply.getSrQty() + ","
+                    + DateUtils.formatOracle(new Date(reply.getSrDelivery())) + ",'" + StringUtils.nvl(reply.getSrRemark(), "")
+                    + "','" + reply.getSrSacode() + "'," + reply.getSrSddetno() + ","
+                    + DateUtils.formatOracle(new Date(reply.getSrDate())) + ",'" + reply.getSrRecorder() + "','"
+                    + StringUtils.nvl(reply.getSrType(), "") + "','已下载')");
+        });
+        jdbcTemplate.batchUpdate(sqlList.toArray(new String[]{}));
+    }
+
+    /**
+     * 获取需要上传平台的saleDown本地回复
+     *
+     * @return
+     */
+    public List<SaleReplyPO> toUploadReplyList() {
+        try {
+            return jdbcTemplate.query("select SaleReply.*,SaleDown.sa_customeruu cu_uu from SaleReply left join SaleDown on sr_sacode=sa_code where SR_SENDSTATUS='待上传' and sa_type='purchase' and sa_customeruu is not null",
+                    new BeanPropertyRowMapper<>(SaleReplyPO.class));
+        } catch (EmptyResultDataAccessException e) {
+            return null;
+        }
+    }
+
+    /**
+     * 结案、反结案saledown
+     *
+     * @param endList
+     */
+    public void saveEndList(final List<SaleDownDetailEnd> endList) {
+        jdbcTemplate.batchUpdate("update SaleDownDetail set sd_mrpstatus=?,sd_mrpstatuscode=? where b2b_pd_id=? and sd_code=? and sd_detno=?", new BatchPreparedStatementSetter() {
+            @Override
+            public void setValues(PreparedStatement ps, int i) throws SQLException {
+                SaleDownDetailEnd end = endList.get(i);
+                Status status = (null != end && Const.YES == Math.abs(end.getSdEnded())) ? Status.FINISH : Status.AUDITED;
+                ps.setObject(1, status.display());
+                ps.setObject(2, status.code());
+                ps.setObject(3, end.getB2BPdId());
+                ps.setObject(4, end.getSdCode());
+                ps.setObject(5, end.getSdDetno());
+            }
+
+            @Override
+            public int getBatchSize() {
+                return endList.size();
+            }
+        });
+    }
+
+    /**
+     * 标记本地回复已上传到平台
+     *
+     * @param replyList
+     */
+    public void setReplyUploaded(final List<SaleReplyPO> replyList) {
+        List<Integer> idList = replyList.stream().map(reply -> reply.getSr_id()).distinct().collect(Collectors.toList());
+        Map<String, Object> params = new HashMap<>(1);
+        params.put("ids", idList);
+        namedJdbcTemplate.update("update SaleReply set sr_sendstatus='已下载' where sr_id in (:ids)", params);
+    }
+}

+ 24 - 0
uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/task/AbstractB2bTask.java

@@ -0,0 +1,24 @@
+package com.usoftchina.uas.pl.b2b.task;
+
+import com.usoft.b2b.external.api.entity.RespHeader;
+import com.usoftchina.uas.pl.b2b.config.B2bSdk;
+import com.usoftchina.uas.pl.b2b.exception.ResponseError;
+import com.usoftchina.uas.pl.task.AbstractTask;
+import com.usoftchina.uas.pl.utils.Const;
+import org.springframework.beans.factory.annotation.Autowired;
+
+/**
+ * @author yingp
+ * @date 2020/1/17
+ */
+public abstract class AbstractB2bTask extends AbstractTask {
+
+    @Autowired
+    protected B2bSdk sdk;
+
+    protected static void assertOk(RespHeader header) {
+        if (Const.OK != header.getCode()) {
+            throw new ResponseError(header);
+        }
+    }
+}

+ 59 - 0
uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/task/PurchaseBillTask.java

@@ -0,0 +1,59 @@
+package com.usoftchina.uas.pl.b2b.task;
+
+import com.usoft.b2b.external.erp.invoice.api.protobuf.SaveApBillsReq;
+import com.usoft.b2b.external.erp.invoice.api.protobuf.SaveApBillsResp;
+import com.usoftchina.uas.pl.annotation.Method;
+import com.usoftchina.uas.pl.annotation.Role;
+import com.usoftchina.uas.pl.annotation.TaskMapping;
+import com.usoftchina.uas.pl.context.TaskThreadContext;
+import com.usoftchina.uas.pl.exception.DataConsistencyException;
+import com.usoftchina.uas.pl.b2b.po.PurchaseBillPO;
+import com.usoftchina.uas.pl.b2b.service.PurchaseBillService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import org.springframework.util.CollectionUtils;
+
+import java.util.List;
+
+/**
+ * @author yingp
+ * @date 2020/1/15
+ */
+@TaskMapping(module = "bill", title = "应付发票", role = Role.BUYER)
+@Component
+public class PurchaseBillTask extends AbstractB2bTask {
+
+    @Autowired
+    private PurchaseBillService purchaseBillService;
+
+    @TaskMapping(title = "上传应付发票", fixedDelay = 120000, method = Method.UPLOAD)
+    public void saveApBills() throws Exception {
+        List<PurchaseBillPO> billList = purchaseBillService.toUploadBillList();
+        if (!CollectionUtils.isEmpty(billList)) {
+            logger.debug("saveApBills, req count {}", billList.size());
+            TaskThreadContext.get().setData(billList);
+            SaveApBillsReq.Builder req = SaveApBillsReq.newBuilder();
+            billList.forEach(bill -> req.addData(bill.map()));
+            new AbstractUploadHandler<PurchaseBillPO>("apbill", "ab_id", "ab_sendstatus") {
+                @Override
+                protected void handle() throws Exception {
+                    SaveApBillsResp resp = sdk.invoice().saveApBills(req.build());
+                    assertOk(resp.getRespHeader());
+                    if (resp.getDataCount() > 0) {
+                        logger.debug("saveApBills, resp count {}", resp.getDataCount());
+                        try {
+                            // 修改上传状态
+                            purchaseBillService.setBillUploaded(resp.getDataList());
+                        } catch (Exception e) {
+                            throw new DataConsistencyException(billList, e);
+                        }
+                    }
+                }
+
+                @Override
+                protected void onSuccess() {
+                }
+            }.run(billList);
+        }
+    }
+}

+ 98 - 0
uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/task/PurchaseChangeTask.java

@@ -0,0 +1,98 @@
+package com.usoftchina.uas.pl.b2b.task;
+
+import com.alibaba.fastjson.JSON;
+import com.usoft.b2b.external.erp.order.api.entity.PurchaseChangeReply;
+import com.usoft.b2b.external.erp.order.api.protobuf.*;
+import com.usoftchina.uas.pl.annotation.Method;
+import com.usoftchina.uas.pl.annotation.Role;
+import com.usoftchina.uas.pl.annotation.TaskMapping;
+import com.usoftchina.uas.pl.context.TaskThreadContext;
+import com.usoftchina.uas.pl.b2b.po.PurchaseChangePO;
+import com.usoftchina.uas.pl.b2b.service.PurchaseChangeService;
+import com.usoftchina.uas.pl.utils.CollectionUtils;
+import com.usoftchina.uas.pl.utils.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * @author yingp
+ * @date 2020/1/13
+ */
+@TaskMapping(module = "order", title = "采购变更", role = Role.BUYER)
+@Component
+public class PurchaseChangeTask extends AbstractB2bTask {
+
+    @Autowired
+    private PurchaseChangeService purchaseChangeService;
+
+    @TaskMapping(title = "上传采购变更单", fixedDelay = 60000, method = Method.UPLOAD)
+    public void savePurchaseChangeList() throws Exception {
+        final List<PurchaseChangePO> changeList = purchaseChangeService.toUploadList();
+        if (!CollectionUtils.isEmpty(changeList)) {
+            logger.debug("savePurchaseChangeList, req count {}", changeList.size());
+            TaskThreadContext.get().setData(changeList);
+            final SavePurchaseChangeListReq.Builder req = SavePurchaseChangeListReq.newBuilder();
+            changeList.forEach(purchase -> {
+                req.addPurchaseChangeList(purchase.map());
+            });
+            new AbstractUploadHandler<PurchaseChangePO>("purchasechange", "pc_id", "pc_sendstatus") {
+                @Override
+                protected void handle() throws Exception {
+                    sdk.order().savePurchaseChangeList(req.build());
+                }
+            }.run(changeList);
+        }
+    }
+
+    @TaskMapping(title = "从平台下载供应商对变更单的回复信息", fixedDelay = 60000, method = Method.DOWNLOAD)
+    public void getPurchaseChangeReplyList() throws Exception {
+        GetPurchaseChangeReplyListReq.Builder req = GetPurchaseChangeReplyListReq.newBuilder();
+        GetPurchaseChangeReplyListResp resp = sdk.order().getPurchaseChangeReplyList(req.build());
+        assertOk(resp.getRespHeader());
+        if (resp.getReplyListCount() > 0) {
+            logger.debug("getPurchaseChangeReplyList, resp count {}", resp.getReplyListCount());
+            TaskThreadContext.get().setDataSize(resp.getReplyListCount());
+            TaskThreadContext.tx().run(() -> {
+                purchaseChangeService.saveReplyList(resp.getReplyListList());
+                // 回执
+                updatePurchaseChangeReplyStatus(resp.getReplyListList());
+            });
+            // 发消息
+            sendMessageWhenReplied(resp.getReplyListList());
+        }
+    }
+
+    /**
+     * 发送消息
+     *
+     * @param replyList
+     */
+    private void sendMessageWhenReplied(List<PurchaseChangeReply> replyList) {
+        Map<String, Object> paramsMap = new HashMap<>(1);
+        paramsMap.put("codes", replyList.stream().map(reply -> reply.getPcCode()).distinct().collect(Collectors.toList()));
+        List<Integer> idList = namedJdbcTemplate.queryForList("select pc_id from purchasechange where pc_code in (:codes)", paramsMap,
+                Integer.class);
+        if (!CollectionUtils.isEmpty(idList)) {
+            createMessage("PurchaseChange", StringUtils.collectionToCommaDelimitedString(idList), "confirm");
+        }
+    }
+
+    /**
+     * 平台的变更单回复信息传到ERP之后,修改平台里面的变更单的回复状态
+     *
+     * @param replyList
+     */
+    private void updatePurchaseChangeReplyStatus(List<PurchaseChangeReply> replyList) throws IOException {
+        String idStr = replyList.stream().map(reply -> String.valueOf(reply.getB2BPcId())).distinct().collect(Collectors.joining(","));
+        UpdatePurchaseChangeReplyStatusReq.Builder req = UpdatePurchaseChangeReplyStatusReq.newBuilder();
+        req.setIdStr(idStr);
+        UpdatePurchaseChangeReplyStatusResp resp = sdk.order().updatePurchaseChangeReplyStatus(req.build());
+        assertOk(resp.getRespHeader());
+    }
+}

+ 76 - 0
uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/task/PurchaseCheckTask.java

@@ -0,0 +1,76 @@
+package com.usoftchina.uas.pl.b2b.task;
+
+import com.usoft.b2b.external.erp.reconciliation.api.entity.PurchaseApCheck;
+import com.usoft.b2b.external.erp.reconciliation.api.protobuf.*;
+import com.usoftchina.uas.pl.annotation.Method;
+import com.usoftchina.uas.pl.annotation.Role;
+import com.usoftchina.uas.pl.annotation.TaskMapping;
+import com.usoftchina.uas.pl.context.TaskThreadContext;
+import com.usoftchina.uas.pl.exception.DataConsistencyException;
+import com.usoftchina.uas.pl.b2b.po.SaleCheckPO;
+import com.usoftchina.uas.pl.b2b.service.PurchaseCheckService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import org.springframework.util.CollectionUtils;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * @author yingp
+ * @date 2020/1/15
+ */
+@TaskMapping(module = "check", title = "应付对账", role = Role.BUYER)
+@Component
+public class PurchaseCheckTask extends AbstractB2bTask {
+
+    @Autowired
+    private PurchaseCheckService purchaseCheckService;
+
+    @TaskMapping(title = "从平台下载应付对账单", fixedDelay = 60000, method = Method.DOWNLOAD)
+    public void getApCheckList() throws Exception {
+        GetApCheckListReq.Builder req = GetApCheckListReq.newBuilder();
+        GetApCheckListResp resp = sdk.reconciliation().getApCheckList(req.build());
+        assertOk(resp.getRespHeader());
+        if (resp.getApCheckListCount() > 0) {
+            logger.debug("getApCheckList, resp count {}", resp.getApCheckListCount());
+            TaskThreadContext.get().setDataSize(resp.getApCheckListCount());
+            TaskThreadContext.tx().run(() -> {
+                purchaseCheckService.saveCheckList(resp.getApCheckListList());
+                // 回执
+                onApCheckSuccess(resp.getApCheckListList());
+            });
+        }
+    }
+
+    /**
+     * 平台的应收对账传到供应商ERP之后,修改平台里面的订单的上传状态
+     *
+     * @param checkList
+     */
+    private void onApCheckSuccess(List<PurchaseApCheck> checkList) throws IOException {
+        String idStr = checkList.stream().map(check -> String.valueOf(check.getAcB2Bid())).distinct().collect(Collectors.joining(","));
+        OnApChcekSuccessReq.Builder req = OnApChcekSuccessReq.newBuilder();
+        req.setIdStr(idStr);
+        OnApChcekSuccessResp resp = sdk.reconciliation().onApCheckSuccess(req.build());
+        assertOk(resp.getRespHeader());
+    }
+
+    @TaskMapping(title = "上传应付对账单回复账单", fixedDelay = 60000, method = Method.UPLOAD)
+    public void replyApCheck() throws IOException {
+        List<SaleCheckPO> checkList = purchaseCheckService.toUploadReplyList();
+        if (!CollectionUtils.isEmpty(checkList)) {
+            logger.debug("replyApCheck, req count {}", checkList.size());
+            TaskThreadContext.get().setData(checkList);
+            ReplyApCheckReq.Builder req = ReplyApCheckReq.newBuilder();
+            ReplyApCheckResp resp = sdk.reconciliation().replyApCheck(req.build());
+            assertOk(resp.getRespHeader());
+            try {
+                purchaseCheckService.setReplyListUploaded(checkList);
+            } catch (Exception e) {
+                throw new DataConsistencyException(checkList, e);
+            }
+        }
+    }
+}

+ 103 - 0
uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/task/PurchaseInOutTask.java

@@ -0,0 +1,103 @@
+package com.usoftchina.uas.pl.b2b.task;
+
+import com.usoft.b2b.external.erp.deliver.api.protobuf.*;
+import com.usoftchina.uas.pl.annotation.Method;
+import com.usoftchina.uas.pl.annotation.Role;
+import com.usoftchina.uas.pl.annotation.TaskMapping;
+import com.usoftchina.uas.pl.context.TaskThreadContext;
+import com.usoftchina.uas.pl.exception.DataConsistencyException;
+import com.usoftchina.uas.pl.b2b.po.PurchaseProdInOutPO;
+import com.usoftchina.uas.pl.b2b.service.PurchaseInOutService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import org.springframework.util.CollectionUtils;
+
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * @author yingp
+ * @date 2020/1/14
+ */
+@TaskMapping(module = "inout", title = "采购验收/退", role = Role.BUYER)
+@Component
+public class PurchaseInOutTask extends AbstractB2bTask {
+
+    @Autowired
+    private PurchaseInOutService purchaseInOutService;
+
+    @TaskMapping(title = "上传采购验收单(已过账)", fixedDelay = 60000, method = Method.UPLOAD)
+    public void savePurchaseProdInOut() throws IOException {
+        List<PurchaseProdInOutPO> inOutList = purchaseInOutService.toUploadList("采购验收单");
+        if (!CollectionUtils.isEmpty(inOutList)) {
+            logger.debug("savePurchaseProdInOut, req count {}", inOutList.size());
+            TaskThreadContext.get().setData(inOutList);
+            SavePurchaseProdInOutReq.Builder req = SavePurchaseProdInOutReq.newBuilder();
+            inOutList.forEach(inOut -> req.addData(inOut.map()));
+            SavePurchaseProdInOutResp resp = sdk.deliver().savePurchaseProdInOut(req.build());
+            if (resp.getDataCount() > 0) {
+                logger.debug("savePurchaseProdInOut, resp count {}", resp.getDataCount());
+                try {
+                    purchaseInOutService.setUploaded(resp.getDataList());
+                } catch (Exception e) {
+                    throw new DataConsistencyException(inOutList, e);
+                }
+            }
+        }
+    }
+
+    @TaskMapping(title = "上传已反过账的采购验收单", fixedDelay = 60000, method = Method.UPLOAD)
+    public void nonPostingProdInOut() throws IOException {
+        List<PurchaseProdInOutPO> inOutList = purchaseInOutService.toUploadUnList("采购验收单");
+        if (!CollectionUtils.isEmpty(inOutList)) {
+            logger.debug("nonPostingProdInOut, req count {}", inOutList.size());
+            TaskThreadContext.get().setData(inOutList);
+            NonPostingProdInOutReq.Builder req = NonPostingProdInOutReq.newBuilder();
+            inOutList.forEach(inOut -> req.addData(inOut.map()));
+            NonPostingProdInOutResp resp = sdk.deliver().nonPostingProdInOut(req.build());
+            assertOk(resp.getRespHeader());
+            try {
+                purchaseInOutService.setUploaded2(inOutList);
+            } catch (Exception e) {
+                throw new DataConsistencyException(inOutList, e);
+            }
+        }
+    }
+
+    @TaskMapping(title = "上传采购验退单", fixedDelay = 60000, method = Method.UPLOAD)
+    public void savePurchaseProdReturn() throws IOException {
+        List<PurchaseProdInOutPO> inOutList = purchaseInOutService.toUploadList("采购验退单");
+        if (!CollectionUtils.isEmpty(inOutList)) {
+            logger.debug("savePurchaseProdReturn, req count {}", inOutList.size());
+            TaskThreadContext.get().setData(inOutList);
+            SavePurchaseProdReturnReq.Builder req = SavePurchaseProdReturnReq.newBuilder();
+            inOutList.forEach(inOut -> req.addData(inOut.map()));
+            SavePurchaseProdReturnResp resp = sdk.deliver().savePurchaseProdReturn(req.build());
+            if (resp.getDataCount() > 0) {
+                logger.debug("savePurchaseProdReturn, resp count {}", resp.getDataCount());
+                try {
+                    purchaseInOutService.setUploaded(resp.getDataList());
+                } catch (Exception e) {
+                    throw new DataConsistencyException(inOutList, e);
+                }
+            }
+        }
+    }
+
+    @TaskMapping(title = "上传已反过账的采购验退单", fixedDelay = 60000, method = Method.UPLOAD)
+    public void nonPostingProdReturn() throws IOException {
+        List<PurchaseProdInOutPO> inOutList = purchaseInOutService.toUploadUnList("采购验退单");
+        if (!CollectionUtils.isEmpty(inOutList)) {
+            logger.debug("nonPostingProdReturn, req count {}", inOutList.size());
+            TaskThreadContext.get().setData(inOutList);
+            NonPostingProdReturnReq.Builder req = NonPostingProdReturnReq.newBuilder();
+            inOutList.forEach(inOut -> req.addData(inOut.map()));
+            sdk.deliver().nonPostingProdReturn(req.build());
+            try {
+                purchaseInOutService.setUploaded2(inOutList);
+            } catch (Exception e) {
+                throw new DataConsistencyException(inOutList, e);
+            }
+        }
+    }
+}

+ 221 - 0
uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/task/PurchaseNotifyTask.java

@@ -0,0 +1,221 @@
+package com.usoftchina.uas.pl.b2b.task;
+
+import com.usoft.b2b.external.erp.deliver.api.entity.AcceptNotify;
+import com.usoft.b2b.external.erp.deliver.api.protobuf.*;
+import com.usoftchina.uas.pl.annotation.Method;
+import com.usoftchina.uas.pl.annotation.Role;
+import com.usoftchina.uas.pl.annotation.TaskMapping;
+import com.usoftchina.uas.pl.context.TaskThreadContext;
+import com.usoftchina.uas.pl.exception.DataConsistencyException;
+import com.usoftchina.uas.pl.b2b.po.AcceptNotifyConfirmPO;
+import com.usoftchina.uas.pl.b2b.po.AcceptNotifyPO;
+import com.usoftchina.uas.pl.b2b.po.AcceptNotifyVerifyPO;
+import com.usoftchina.uas.pl.b2b.po.PurchaseNotifyPO;
+import com.usoftchina.uas.pl.b2b.service.PurchaseNotifyService;
+import com.usoftchina.uas.pl.utils.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import org.springframework.util.CollectionUtils;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+/**
+ * @author yingp
+ * @date 2020/1/14
+ */
+@TaskMapping(module = "inout", title = "送货提醒", role = Role.BUYER)
+@Component
+public class PurchaseNotifyTask extends AbstractB2bTask {
+
+    @Autowired
+    private PurchaseNotifyService purchaseNotifyService;
+
+    @TaskMapping(title = "上传送货提醒", fixedDelay = 30000, method = Method.UPLOAD)
+    public void savePurchaseNotify() throws Exception {
+        final List<PurchaseNotifyPO> notifyList = purchaseNotifyService.toUploadPurchaseNotifyList();
+        if (!CollectionUtils.isEmpty(notifyList)) {
+            logger.debug("savePurchaseNotify, req count {}", notifyList.size());
+            TaskThreadContext.get().setData(notifyList);
+            SavePurchaseNotifyReq.Builder req = SavePurchaseNotifyReq.newBuilder();
+            notifyList.forEach(notify -> req.addPurchaseNotifyList(notify.map()));
+            new AbstractUploadHandler<PurchaseNotifyPO>("purchaseNotify", "pn_id", "pn_sendStatus") {
+
+                @Override
+                protected void handle() throws Exception {
+                    SavePurchaseNotifyResp resp = sdk.deliver().savePurchaseNotify(req.build());
+                    assertOk(resp.getRespHeader());
+                    if (resp.getPurchaseNotifyListCount() > 0) {
+                        logger.debug("savePurchaseNotify, resp count {}", resp.getPurchaseNotifyListCount());
+                        try {
+                            purchaseNotifyService.setPurchaseNotifyUploaded(resp.getPurchaseNotifyListList());
+                        } catch (Exception e) {
+                            throw new DataConsistencyException(notifyList, e);
+                        }
+                    }
+                }
+
+                @Override
+                protected void onSuccess() {
+                }
+            }.run(notifyList);
+        }
+    }
+
+    @TaskMapping(title = "从平台下载供应商下达的发货单", fixedDelay = 30000, method = Method.DOWNLOAD)
+    public void getAcceptNotifyList() throws Exception {
+        GetAcceptNotifyListReq.Builder req = GetAcceptNotifyListReq.newBuilder();
+        GetAcceptNotifyListResp resp = sdk.deliver().getAcceptNotifyList(req.build());
+        assertOk(resp.getRespHeader());
+        if (resp.getAcceptNotifyListCount() > 0) {
+            logger.debug("getAcceptNotifyList, resp count {}", resp.getAcceptNotifyListCount());
+            TaskThreadContext.get().setDataSize(resp.getAcceptNotifyListCount());
+            AtomicReference<Set<Integer>> anIdSet = new AtomicReference<>();
+            TaskThreadContext.tx().run(() -> {
+                anIdSet.set(purchaseNotifyService.saveAcceptNotifyList(resp.getAcceptNotifyListList()));
+                // 回执
+                updateAcceptNotifyStatus(resp.getAcceptNotifyListList());
+            });
+            // 发消息
+            createMessage("AcceptNotify", StringUtils.collectionToCommaDelimitedString(anIdSet.get()), "confirm");
+        }
+    }
+
+    /**
+     * 平台的发货单传到ERP之后,修改平台里面的发货单的状态
+     *
+     * @param acceptNotifyList
+     */
+    private void updateAcceptNotifyStatus(List<AcceptNotify> acceptNotifyList) throws IOException {
+        String idStr = acceptNotifyList.stream().map(accept -> String.valueOf(accept.getB2BSsId())).distinct().collect(Collectors.joining(","));
+        UpdateAcceptNotifyStatusReq.Builder req = UpdateAcceptNotifyStatusReq.newBuilder();
+        req.setIdstr(idStr);
+        sdk.deliver().updateAcceptNotifyStatus(req.build());
+    }
+
+    @TaskMapping(title = "上传主动维护的收料通知到平台", fixedDelay = 60000, method = Method.UPLOAD)
+    public void saveAcceptNotify() throws IOException {
+        List<AcceptNotifyPO> acceptList = purchaseNotifyService.toUploadAcceptNotifyList();
+        if (!CollectionUtils.isEmpty(acceptList)) {
+            logger.debug("saveAcceptNotify, req count {}", acceptList.size());
+            TaskThreadContext.get().setData(acceptList);
+            SaveAcceptNotifyListReq.Builder req = SaveAcceptNotifyListReq.newBuilder();
+            acceptList.forEach(accept -> req.addAcceptNotifyList(accept.map()));
+            SaveAcceptNotifyListResp resp = sdk.deliver().saveAcceptNotify(req.build());
+            assertOk(resp.getRespHeader());
+            if (resp.getAcceptNotifyListCount() > 0) {
+                logger.debug("saveAcceptNotify, resp count {}", resp.getAcceptNotifyListCount());
+                try {
+                    purchaseNotifyService.setAcceptNotifyUploaded(resp.getAcceptNotifyListList());
+                } catch (Exception e) {
+                    throw new DataConsistencyException(acceptList, e);
+                }
+            }
+        }
+    }
+
+    @TaskMapping(title = "上传结案送货提醒", fixedDelay = 60000, method = Method.UPLOAD)
+    public void updatePurchaseNotifyEnd() throws IOException {
+        List<PurchaseNotifyPO> notifyList = purchaseNotifyService.toUploadPurchaseNotifyEndList();
+        if (!CollectionUtils.isEmpty(notifyList)) {
+            logger.debug("updatePurchaseNotifyEnd, req count {}", notifyList.size());
+            TaskThreadContext.get().setData(notifyList);
+            UpdatePurchaseNotifyEndReq.Builder req = UpdatePurchaseNotifyEndReq.newBuilder();
+            notifyList.forEach(notify -> req.addPurchaseNotifyList(notify.map()));
+            UpdatePurchaseNotifyEndResp resp = sdk.deliver().updatePurchaseNotifyEnd(req.build());
+            assertOk(resp.getRespHeader());
+            String[] idArray = resp.getIdStr().split(",");
+            if (idArray.length > 0) {
+                logger.debug("updatePurchaseNotifyEnd, resp count {}", idArray.length);
+                try {
+                    purchaseNotifyService.setPurchaseNotifyEndUploaded(idArray);
+                } catch (Exception e) {
+                    throw new DataConsistencyException(notifyList, e);
+                }
+            }
+        }
+    }
+
+    @TaskMapping(title = "上传收料通知修改的确认数", fixedDelay = 60000, method = Method.UPLOAD)
+    public void saveAcceptNotifyConfirm() throws IOException {
+        List<AcceptNotifyConfirmPO> confirmList = purchaseNotifyService.toUploadConfirmList();
+        if (!CollectionUtils.isEmpty(confirmList)) {
+            logger.debug("saveAcceptNotifyConfirm, req count {}", confirmList.size());
+            TaskThreadContext.get().setData(confirmList);
+            SaveAcceptNotifyConfirmListReq.Builder req = SaveAcceptNotifyConfirmListReq.newBuilder();
+            confirmList.forEach(confirm -> req.addAcceptNotifyConfirmList(confirm.map()));
+            SaveAcceptNotifyConfirmListResp resp = sdk.deliver().saveAcceptNotifyConfirm(req.build());
+            assertOk(resp.getRespHeader());
+            try {
+                // 修改状态
+                purchaseNotifyService.setConfirmListUploaded(confirmList);
+            } catch (Exception e) {
+                throw new DataConsistencyException(confirmList, e);
+            }
+        }
+    }
+
+    @TaskMapping(title = "上传已审核的收料单收料数", fixedDelay = 60000)
+    public void saveAcceptNotifyVerify() throws Exception {
+        final List<AcceptNotifyVerifyPO> verifyList = purchaseNotifyService.toUploadVerifyList();
+        if (!CollectionUtils.isEmpty(verifyList)) {
+            logger.debug("saveAcceptNotifyVerify, req count {}", verifyList.size());
+            TaskThreadContext.get().setData(verifyList);
+            SaveAcceptNotifyVerifyListReq.Builder req = SaveAcceptNotifyVerifyListReq.newBuilder();
+            verifyList.forEach(verify -> req.addVerifyList(verify.map()));
+            new AbstractUploadHandler<AcceptNotifyVerifyPO>("verifyapplydetail", "vad_id", "vad_sendstatus") {
+
+                @Override
+                protected void handle() throws Exception {
+                    SaveAcceptNotifyVerifyListResp resp = sdk.deliver().saveAcceptNotifyVerify(req.build());
+                    assertOk(resp.getRespHeader());
+                }
+            }.run(verifyList);
+        }
+    }
+
+    @TaskMapping(title = "上传反审核的收料单收料数", fixedDelay = 60000)
+    public void saveUnAcceptNotifyVerify() throws IOException {
+        List<AcceptNotifyVerifyPO> verifyList = purchaseNotifyService.toUploadUnVerifyList();
+        if (!CollectionUtils.isEmpty(verifyList)) {
+            logger.debug("saveUnAcceptNotifyVerify, req count {}", verifyList.size());
+            TaskThreadContext.get().setData(verifyList);
+            SaveUnAcceptNotifyVerifyListReq.Builder req = SaveUnAcceptNotifyVerifyListReq.newBuilder();
+            verifyList.forEach(verify -> req.addVerifyList(verify.map()));
+            SaveUnAcceptNotifyVerifyListResp resp = sdk.deliver().saveUnAcceptNotifyVerify(req.build());
+            assertOk(resp.getRespHeader());
+            // 修改状态
+            try {
+                purchaseNotifyService.setVerifyListUploaded(verifyList);
+            } catch (Exception e) {
+                throw new DataConsistencyException(verifyList, e);
+            }
+        }
+    }
+
+    @TaskMapping(title = "校验结案送货提醒", cron = "0 0 8-18 * * ? ", method = Method.UPLOAD)
+    public void checkPurchaseNotify() {
+        // 每次最多传输数据
+        int maxSeed = 100;
+        List<PurchaseNotifyPO> notifyList = purchaseNotifyService.lastHourPurchaseNotifyEndList();
+        if (!CollectionUtils.isEmpty(notifyList)) {
+            logger.debug("checkPurchaseNotify, req count {}", notifyList.size());
+            TaskThreadContext.get().setDataSize(notifyList.size());
+            Stream.iterate(0, n -> n + 1)
+                    .limit((int) Math.ceil((double) notifyList.size() / maxSeed)).forEach(page -> {
+                CheckPurchaseNotifyReq.Builder req = CheckPurchaseNotifyReq.newBuilder();
+                notifyList.stream().skip(page * maxSeed).limit(maxSeed)
+                        .forEach(notify -> req.addPurchaseNotifyList(notify.map()));
+                try {
+                    sdk.deliver().checkPurchaseNotify(req.build());
+                } catch (IOException e) {
+                    throw new RuntimeException(e);
+                }
+            });
+        }
+    }
+}

+ 153 - 0
uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/task/PurchaseTask.java

@@ -0,0 +1,153 @@
+package com.usoftchina.uas.pl.b2b.task;
+
+import com.usoft.b2b.external.erp.order.api.entity.MessageLog;
+import com.usoft.b2b.external.erp.order.api.entity.PurchaseReply;
+import com.usoft.b2b.external.erp.order.api.protobuf.*;
+import com.usoftchina.uas.pl.annotation.Method;
+import com.usoftchina.uas.pl.annotation.Role;
+import com.usoftchina.uas.pl.annotation.TaskMapping;
+import com.usoftchina.uas.pl.context.TaskThreadContext;
+import com.usoftchina.uas.pl.exception.DataConsistencyException;
+import com.usoftchina.uas.pl.b2b.po.PurchaseDetailEndPO;
+import com.usoftchina.uas.pl.b2b.po.PurchasePO;
+import com.usoftchina.uas.pl.b2b.po.PurchaseReplyPO;
+import com.usoftchina.uas.pl.b2b.service.PurchaseService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import org.springframework.util.CollectionUtils;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * @author yingp
+ * @date 2020/1/13
+ */
+@TaskMapping(module = "order", title = "采购", role = Role.BUYER)
+@Component
+public class PurchaseTask extends AbstractB2bTask {
+    @Autowired
+    private PurchaseService purchaseService;
+
+    @TaskMapping(title = "上传采购订单", fixedDelay = 30000, method = Method.UPLOAD)
+    public void savePurchaseList() throws Exception{
+        List<PurchasePO> purchaseList = purchaseService.toUploadList();
+        if (!CollectionUtils.isEmpty(purchaseList)) {
+            logger.debug("savePurchaseList, req count {}", purchaseList.size());
+            TaskThreadContext.get().setData(purchaseList);
+            SavePurchaseListReq.Builder req = SavePurchaseListReq.newBuilder();
+            purchaseList.forEach(purchase -> {
+                req.addData(purchase.map());
+            });
+            SavePurchaseListResp resp = sdk.order().savePurchaseList(req.build());
+            assertOk(resp.getRespHeader());
+            if (resp.getDataCount() > 0) {
+                logger.debug("savePurchaseList, resp count {}", resp.getDataCount());
+                try {
+                    purchaseService.setUploaded(resp.getDataList());
+                } catch (Exception e) {
+                    throw new DataConsistencyException(purchaseList, e);
+                }
+            }
+        }
+    }
+
+    @TaskMapping(title = "从平台下载供应商的回复记录", fixedDelay = 30000, method = Method.DOWNLOAD)
+    public void getPurchaseReplyList() throws Exception{
+        GetPurchaseReplyListReq.Builder req = GetPurchaseReplyListReq.newBuilder();
+        GetPurchaseReplyListResp resp = sdk.order().getPurchaseReplyList(req.build());
+        assertOk(resp.getRespHeader());
+        if (resp.getDataCount() > 0) {
+            logger.debug("getPurchaseReplyList, resp count {}", resp.getDataCount());
+            TaskThreadContext.get().setDataSize(resp.getDataCount());
+            TaskThreadContext.tx().run(() -> {
+                purchaseService.saveReplyList(resp.getDataList());
+                // 修改平台里面的回复记录的状态
+                updatePurchaseReplyStatus(resp.getDataList());
+            });
+        }
+    }
+
+    /**
+     * 平台的订单回复传到ERP之后,修改平台里面的回复记录的状态
+     *
+     * @param replyList
+     */
+    private void updatePurchaseReplyStatus(List<PurchaseReply> replyList) throws Exception{
+        String idStr = replyList.stream().map(reply -> String.valueOf(reply.getB2BPrId())).distinct().collect(Collectors.joining(","));
+        UpdatePurchaseReplyStatusReq.Builder req = UpdatePurchaseReplyStatusReq.newBuilder();
+        req.setIdStr(idStr);
+        UpdatePurchaseReplyStatusResp resp = sdk.order().updatePurchaseReplyStatus(req.build());
+        assertOk(resp.getRespHeader());
+    }
+
+    @TaskMapping(title = "上传结案、反结案采购订单", fixedDelay = 60000, method = Method.UPLOAD)
+    public void updatePurchaseDetailEnd() throws Exception{
+        List<PurchaseDetailEndPO> detailEndList = purchaseService.toUploadEndList();
+        if (!CollectionUtils.isEmpty(detailEndList)) {
+            logger.debug("updatePurchaseDetailEnd, req count {}", detailEndList.size());
+            TaskThreadContext.get().setData(detailEndList);
+            UpdatePurchaseDetailEndReq.Builder req = UpdatePurchaseDetailEndReq.newBuilder();
+            detailEndList.forEach(end -> {
+                req.addData(end.map());
+            });
+            UpdatePurchaseDetailEndResp resp = sdk.order().updatePurchaseDetailEnd(req.build());
+            assertOk(resp.getRespHeader());
+            try {
+                // 修改上传状态
+                purchaseService.setEndUploaded(detailEndList);
+            } catch (Exception e) {
+                throw new DataConsistencyException(detailEndList, e);
+            }
+        }
+    }
+
+    @TaskMapping(title = "从平台下载打印日志", fixedDelay = 120000, method = Method.DOWNLOAD)
+    public void getPrintLogList() throws Exception{
+        GetMessageLogListReq.Builder req = GetMessageLogListReq.newBuilder();
+        GetMessageLogListResp resp = sdk.order().getMessageLogList(req.build());
+        assertOk(resp.getRespHeader());
+        if (resp.getDataCount() > 0) {
+            logger.debug("getPrintLogList, resp count {}", resp.getDataCount());
+            TaskThreadContext.get().setDataSize(resp.getDataCount());
+            TaskThreadContext.tx().run(() -> {
+                purchaseService.savePrintLogList(resp.getDataList());
+                updatePrintLogStatus(resp.getDataList());
+            });
+        }
+    }
+
+    /**
+     * 平台的打印记录传到ERP之后,修改平台里面的打印记录的传输状态
+     *
+     * @param logList
+     */
+    private void updatePrintLogStatus(List<MessageLog> logList) throws Exception{
+        String idStr = logList.stream().map(log -> log.getCode()).collect(Collectors.joining(","));
+        UpdateMessageLogStatusReq.Builder req = UpdateMessageLogStatusReq.newBuilder();
+        req.setIdStr(idStr);
+        UpdateMessageLogStatusResp resp = sdk.order().updateMessageLogStatus(req.build());
+        assertOk(resp.getRespHeader());
+    }
+
+    @TaskMapping(title = "上传主动回复的记录到平台", fixedDelay = 60000, method = Method.UPLOAD)
+    public void savePurchaseReplyList() throws Exception {
+        List<PurchaseReplyPO> replyList = purchaseService.toUploadReplyList();
+        if (!CollectionUtils.isEmpty(replyList)) {
+            logger.debug("savePurchaseReplyList, req count {}", replyList.size());
+            TaskThreadContext.get().setData(replyList);
+            SavePurchaseReplyListReq.Builder req = SavePurchaseReplyListReq.newBuilder();
+            replyList.forEach(reply -> {
+                req.addData(reply.map());
+            });
+            SavePurchaseReplyListResp resp = sdk.order().savePurchaseReplyList(req.build());
+            assertOk(resp.getRespHeader());
+            // 修改上传状态
+            try {
+                purchaseService.setReplyUploaded(replyList);
+            } catch (Exception e) {
+                throw new DataConsistencyException(replyList, e);
+            }
+        }
+    }
+}

+ 59 - 0
uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/task/SaleBillTask.java

@@ -0,0 +1,59 @@
+package com.usoftchina.uas.pl.b2b.task;
+
+import com.usoft.b2b.external.erp.invoice.api.entity.APBill;
+import com.usoft.b2b.external.erp.invoice.api.protobuf.GetSaleAPBillsReq;
+import com.usoft.b2b.external.erp.invoice.api.protobuf.GetSaleAPBillsResp;
+import com.usoft.b2b.external.erp.invoice.api.protobuf.OnSaleAPBillDownSuccessReq;
+import com.usoft.b2b.external.erp.invoice.api.protobuf.OnSaleAPBillDownSuccessResp;
+import com.usoftchina.uas.pl.annotation.Method;
+import com.usoftchina.uas.pl.annotation.Role;
+import com.usoftchina.uas.pl.annotation.TaskMapping;
+import com.usoftchina.uas.pl.context.TaskThreadContext;
+import com.usoftchina.uas.pl.b2b.service.SaleBillService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * @author yingp
+ * @date 2020/1/15
+ */
+@TaskMapping(module = "bill", title = "应付发票", role = Role.SELLER)
+@Component
+public class SaleBillTask extends AbstractB2bTask {
+
+    @Autowired
+    private SaleBillService saleBillService;
+
+    @TaskMapping(title = "从平台下载客户下达到平台的发票", fixedDelay = 60000, method = Method.DOWNLOAD)
+    public void getSaleAPBills() throws Exception {
+        GetSaleAPBillsReq.Builder req = GetSaleAPBillsReq.newBuilder();
+        GetSaleAPBillsResp resp = sdk.invoice().getSaleAPBills(req.build());
+        if (resp.getDataCount() > 0) {
+            logger.debug("getSaleAPBills, resp count {}", resp.getDataCount());
+            TaskThreadContext.get().setDataSize(resp.getDataCount());
+            TaskThreadContext.tx().run(() -> {
+                saleBillService.saveBillList(resp.getDataList());
+                // 回执
+                onSaleAPBillDownSuccess(resp.getDataList());
+            });
+        }
+    }
+
+    /**
+     * 平台的客户应付票据传到供应商ERP之后,修改平台里面的客户应付票据的上传状态
+     *
+     * @param billList
+     * @throws IOException
+     */
+    private void onSaleAPBillDownSuccess(List<APBill> billList) throws IOException {
+        String idStr = billList.stream().map(bill -> String.valueOf(bill.getAbB2Bid())).distinct().collect(Collectors.joining(","));
+        OnSaleAPBillDownSuccessReq.Builder req = OnSaleAPBillDownSuccessReq.newBuilder();
+        req.setIdStr(idStr);
+        OnSaleAPBillDownSuccessResp resp = sdk.invoice().onSaleAPBillDownSuccess(req.build());
+        assertOk(resp.getRespHeader());
+    }
+}

+ 111 - 0
uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/task/SaleChangeTask.java

@@ -0,0 +1,111 @@
+package com.usoftchina.uas.pl.b2b.task;
+
+import com.usoft.b2b.external.erp.order.api.entity.SaleDownChange;
+import com.usoft.b2b.external.erp.order.api.entity.SaleDownChangeReply;
+import com.usoft.b2b.external.erp.order.api.protobuf.*;
+import com.usoftchina.uas.pl.annotation.Method;
+import com.usoftchina.uas.pl.annotation.Role;
+import com.usoftchina.uas.pl.annotation.TaskMapping;
+import com.usoftchina.uas.pl.context.TaskThreadContext;
+import com.usoftchina.uas.pl.exception.DataConsistencyException;
+import com.usoftchina.uas.pl.b2b.po.SaleDownChangeReplyPO;
+import com.usoftchina.uas.pl.b2b.service.SaleChangeService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import org.springframework.util.CollectionUtils;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * @author yingp
+ * @date 2020/1/13
+ */
+@TaskMapping(module = "order", title = "采购变更", role = Role.SELLER)
+@Component
+public class SaleChangeTask extends AbstractB2bTask {
+
+    @Autowired
+    private SaleChangeService saleChangeService;
+
+    @TaskMapping(title = "从平台下载客户下达到平台的采购变更单", fixedDelay = 60000, method = Method.DOWNLOAD)
+    public void getSaleDownChangeList() throws Exception {
+        GetSaleDownChangeListReq.Builder req = GetSaleDownChangeListReq.newBuilder();
+        GetSaleDownChangeListResp resp = sdk.order().getSaleDownChangeList(req.build());
+        assertOk(resp.getRespHeader());
+        if (resp.getSaleDownChangeListCount() > 0) {
+            logger.debug("getSaleDownChangeList, resp count {}", resp.getSaleDownChangeListCount());
+            TaskThreadContext.get().setDataSize(resp.getSaleDownChangeListCount());
+            TaskThreadContext.tx().run(() -> {
+                saleChangeService.saveSaleDownChange(resp.getSaleDownChangeListList());
+                // 回执
+                updateSaleDownChangeStatus(resp.getSaleDownChangeListList());
+            });
+        }
+    }
+
+    /**
+     * 平台的变更单传到供应商ERP之后,修改平台里面的变更单的上传状态
+     *
+     * @param changeList
+     */
+    private void updateSaleDownChangeStatus(List<SaleDownChange> changeList) throws IOException {
+        String idStr = changeList.stream().map(change -> String.valueOf(change.getB2BPcId())).distinct().collect(Collectors.joining(","));
+        UpdateSaleDownChangeStatusReq.Builder req = UpdateSaleDownChangeStatusReq.newBuilder();
+        req.setIdStr(idStr);
+        UpdateSaleDownChangeStatusResp resp = sdk.order().updateSaleDownChangeStatus(req.build());
+        assertOk(resp.getRespHeader());
+    }
+
+    @TaskMapping(title = "下载直接在b2b平台回复的信息,修改到客户采购变更单、客户采购单", fixedDelay = 60000, method = Method.DOWNLOAD)
+    public void getSaleDownChangeReplyList() throws Exception {
+        GetSaleDownChangeReplyListReq.Builder req = GetSaleDownChangeReplyListReq.newBuilder();
+        GetSaleDownChangeReplyListResp resp = sdk.order().getSaleDownChangeReplyList(req.build());
+        assertOk(resp.getRespHeader());
+        if (resp.getChangeReplyListCount() > 0) {
+            logger.debug("getSaleDownChangeReplyList, resp count {}", resp.getChangeReplyListCount());
+            TaskThreadContext.get().setDataSize(resp.getChangeReplyListCount());
+            TaskThreadContext.tx().run(() -> {
+                saleChangeService.saveDownloadedReplyList(resp.getChangeReplyListList());
+                // 回执
+                updateSaleDownChangeReplyStatus(resp.getChangeReplyListList());
+            });
+        }
+    }
+
+    /**
+     * 平台的回复信息传到供应商ERP之后,修改平台里面的变更单的回复信息上传状态
+     *
+     * @param replyList
+     */
+    private void updateSaleDownChangeReplyStatus(List<SaleDownChangeReply> replyList) throws IOException {
+        String idStr = replyList.stream().map(reply -> String.valueOf(reply.getB2BPcId())).distinct().collect(Collectors.joining(","));
+        UpdateSaleDownChangeReplyStatusReq.Builder req = UpdateSaleDownChangeReplyStatusReq.newBuilder();
+        req.setIdStr(idStr);
+        UpdateSaleDownChangeReplyStatusResp resp = sdk.order().updateSaleDownChangeReplyStatus(req.build());
+        assertOk(resp.getRespHeader());
+    }
+
+    @TaskMapping(title = "上传变更单回复信息,修改平台客户采购变更单、客户采购单", fixedDelay = 60000, method = Method.UPLOAD)
+    public void saveSaleDownChangeReply() throws IOException {
+        List<SaleDownChangeReplyPO> replyList = saleChangeService.toUploadReplyList();
+        if (!CollectionUtils.isEmpty(replyList)) {
+            logger.debug("saveSaleDownChangeReply, req count {}", replyList.size());
+            TaskThreadContext.get().setData(replyList);
+            SaveSaleDownChangeReplyReq.Builder req = SaveSaleDownChangeReplyReq.newBuilder();
+            replyList.forEach(reply -> req.addChangeReplyList(reply.map()));
+            SaveSaleDownChangeReplyResp resp = sdk.order().saveSaleDownChangeReply(req.build());
+            assertOk(resp.getRespHeader());
+            if (resp.getChangeReplyListCount() > 0) {
+                logger.debug("saveSaleDownChangeReply, resp count {}", resp.getChangeReplyListCount());
+                try {
+                    // 修改状态
+                    saleChangeService.saveUploadedReplyList(resp.getChangeReplyListList());
+                } catch (Exception e) {
+                    throw new DataConsistencyException(replyList, e);
+                }
+            }
+        }
+    }
+}

+ 145 - 0
uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/task/SaleNotifyTask.java

@@ -0,0 +1,145 @@
+package com.usoftchina.uas.pl.b2b.task;
+
+import com.usoft.b2b.external.erp.deliver.api.entity.SaleNotifyDown;
+import com.usoft.b2b.external.erp.deliver.api.entity.SaleNotifyDownEnd;
+import com.usoft.b2b.external.erp.deliver.api.entity.SaleOut;
+import com.usoft.b2b.external.erp.deliver.api.protobuf.*;
+import com.usoftchina.uas.pl.annotation.Method;
+import com.usoftchina.uas.pl.annotation.Role;
+import com.usoftchina.uas.pl.annotation.TaskMapping;
+import com.usoftchina.uas.pl.context.TaskThreadContext;
+import com.usoftchina.uas.pl.exception.DataConsistencyException;
+import com.usoftchina.uas.pl.b2b.po.SaleOutPO;
+import com.usoftchina.uas.pl.b2b.service.SaleNotifyService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import org.springframework.util.CollectionUtils;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * @author yingp
+ * @date 2020/1/14
+ */
+@TaskMapping(module = "inout", title = "送货提醒", role = Role.SELLER)
+@Component
+public class SaleNotifyTask extends AbstractB2bTask {
+
+    @Autowired
+    private SaleNotifyService saleNotifyService;
+
+    @TaskMapping(title = "从平台下载客户下达到平台的送货提醒", fixedDelay = 60000, method = Method.DOWNLOAD)
+    public void getSaleNotifyDownList() throws Exception {
+        GetSaleNotifyDownListReq.Builder req = GetSaleNotifyDownListReq.newBuilder();
+        GetSaleNotifyDownListResp resp = sdk.deliver().getSaleNotifyDownList(req.build());
+        assertOk(resp.getRespHeader());
+        if (resp.getSaleNotifyDownListCount() > 0) {
+            logger.debug("getSaleNotifyDownList, resp count {}", resp.getSaleNotifyDownListCount());
+            TaskThreadContext.get().setDataSize(resp.getSaleNotifyDownListCount());
+            TaskThreadContext.tx().run(() -> {
+                saleNotifyService.saveSaleNotifyDownList(resp.getSaleNotifyDownListList());
+                // 回执
+                updateSaleNotifyDownStatus(resp.getSaleNotifyDownListList());
+            });
+        }
+    }
+
+    /**
+     * 平台的送货提醒传到供应商ERP之后,修改平台里面的送货提醒的上传状态
+     *
+     * @param notifyList
+     */
+    private void updateSaleNotifyDownStatus(List<SaleNotifyDown> notifyList) throws IOException {
+        String idStr = notifyList.stream().map(notify -> String.valueOf(notify.getB2BPnId())).distinct().collect(Collectors.joining(","));
+        UpdateSaleNotifyDownStatusReq.Builder req = UpdateSaleNotifyDownStatusReq.newBuilder();
+        req.setIdStr(idStr);
+        UpdateSaleNotifyDownStatusResp resp = sdk.deliver().updateSaleNotifyDownStatus(req.build());
+        assertOk(resp.getRespHeader());
+    }
+
+    @TaskMapping(title = "下载直接在平台做的发货单", fixedDelay = 60000, method = Method.DOWNLOAD)
+    public void getSaleOutList() throws Exception {
+        GetSaleOutListReq.Builder req = GetSaleOutListReq.newBuilder();
+        GetSaleOutListResp resp = sdk.deliver().getSaleOutList(req.build());
+        if (resp.getSaleOutListCount() > 0) {
+            logger.debug("getSaleOutList, resp count {}", resp.getSaleOutListCount());
+            TaskThreadContext.get().setDataSize(resp.getSaleOutListCount());
+            TaskThreadContext.tx().run(() -> {
+                saleNotifyService.saveSaleOutList(resp.getSaleOutListList());
+                // 回执
+                updateSaleOutStatus(resp.getSaleOutListList());
+            });
+        }
+    }
+
+    /**
+     * 平台的发货单传到供应商ERP之后,修改平台里面的发货单的上传状态
+     *
+     * @param outList
+     */
+    private void updateSaleOutStatus(List<SaleOut> outList) throws IOException {
+        String idStr = outList.stream().map(out -> String.valueOf(out.getB2BSsId())).collect(Collectors.joining(","));
+        UpdateSaleOutStatusReq.Builder req = UpdateSaleOutStatusReq.newBuilder();
+        req.setIdStr(idStr);
+        UpdateSaleOutStatusResp resp = sdk.deliver().updateSaleOutStatus(req.build());
+        assertOk(resp.getRespHeader());
+    }
+
+    @TaskMapping(title = "上传发货单到平台", fixedDelay = 60000, method = Method.UPLOAD)
+    public void saveSaleOutList() throws Exception {
+        final List<SaleOutPO> outList = saleNotifyService.toUploadSaleOutList();
+        if (!CollectionUtils.isEmpty(outList)) {
+            logger.debug("saveSaleOutList, req count {}", outList.size());
+            TaskThreadContext.get().setData(outList);
+            SaveSaleOutListReq.Builder req = SaveSaleOutListReq.newBuilder();
+            outList.forEach(out -> req.addSaleOutList(out.map()));
+            new AbstractUploadHandler<SaleOutPO>("ProdInOut", "pi_id", "pi_sendstatus") {
+                @Override
+                protected void handle() throws Exception {
+                    SaveSaleOutListResp resp = sdk.deliver().saveSaleOutList(req.build());
+                    assertOk(resp.getRespHeader());
+                }
+
+                @Override
+                protected void onSuccess() {
+                    try {
+                        saleNotifyService.setSaleOutUploaded(outList);
+                    } catch (Exception e) {
+                        throw new DataConsistencyException(outList, e);
+                    }
+                }
+            }.run(outList);
+        }
+    }
+
+    @TaskMapping(title = "从平台下载客户下达到平台的结案、反结案送货提醒", fixedDelay = 60000, method = Method.DOWNLOAD)
+    public void updateSaleNotifyDownEnd() throws Exception {
+        UpdateSaleNotifyDownEndReq.Builder req = UpdateSaleNotifyDownEndReq.newBuilder();
+        UpdateSaleNotifyDownEndResp resp = sdk.deliver().updateSaleNotifyDownEnd(req.build());
+        assertOk(resp.getRespHeader());
+        if (resp.getEndListCount() > 0) {
+            logger.debug("updateSaleNotifyDownEnd, resp count {}", resp.getEndListCount());
+            TaskThreadContext.get().setDataSize(resp.getEndListCount());
+            TaskThreadContext.tx().run(() -> {
+                saleNotifyService.saveNotifyDownEndList(resp.getEndListList());
+                // 回执
+                updateSaleNotifyDownEndStatus(resp.getEndListList());
+            });
+        }
+    }
+
+    /**
+     * 平台的结案、反结案客户送货提醒单传到供应商ERP之后,修改平台里面的上传状态
+     *
+     * @param endList
+     */
+    private void updateSaleNotifyDownEndStatus(List<SaleNotifyDownEnd> endList) throws IOException {
+        String idStr = endList.stream().map(end -> String.valueOf(end.getB2BPnId())).collect(Collectors.joining(","));
+        UpdateSaleNotifyDownEndStatusReq.Builder req = UpdateSaleNotifyDownEndStatusReq.newBuilder();
+        req.setIdStr(idStr);
+        UpdateSaleNotifyDownEndStatusResp resp = sdk.deliver().updateSaleNotifyDownEndStatus(req.build());
+        assertOk(resp.getRespHeader());
+    }
+}

+ 139 - 0
uas-pl-b2b/src/main/java/com/usoftchina/uas/pl/b2b/task/SaleTask.java

@@ -0,0 +1,139 @@
+package com.usoftchina.uas.pl.b2b.task;
+
+import com.usoft.b2b.external.erp.order.api.entity.SaleDown;
+import com.usoft.b2b.external.erp.order.api.entity.SaleDownDetailEnd;
+import com.usoft.b2b.external.erp.order.api.entity.SaleReply;
+import com.usoft.b2b.external.erp.order.api.protobuf.*;
+import com.usoftchina.uas.pl.annotation.Method;
+import com.usoftchina.uas.pl.annotation.Role;
+import com.usoftchina.uas.pl.annotation.TaskMapping;
+import com.usoftchina.uas.pl.context.TaskThreadContext;
+import com.usoftchina.uas.pl.exception.DataConsistencyException;
+import com.usoftchina.uas.pl.b2b.po.SaleReplyPO;
+import com.usoftchina.uas.pl.b2b.service.SaleService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import org.springframework.util.CollectionUtils;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * @author yingp
+ * @date 2020/1/13
+ */
+@TaskMapping(module = "order", title = "采购", role = Role.SELLER)
+@Component
+public class SaleTask extends AbstractB2bTask {
+
+    @Autowired
+    private SaleService saleService;
+
+    @TaskMapping(title = "从平台下载客户下达到平台的采购订单", fixedDelay = 60000, method = Method.DOWNLOAD)
+    public void getSaleDownList() throws Exception {
+        GetSaleDownListReq.Builder req = GetSaleDownListReq.newBuilder();
+        GetSaleDownListResp resp = sdk.order().getSaleDownList(req.build());
+        assertOk(resp.getRespHeader());
+        if (resp.getSaleDownListCount() > 0) {
+            logger.debug("getSaleDownList, resp count {}", resp.getSaleDownListCount());
+            TaskThreadContext.get().setDataSize(resp.getSaleDownListCount());
+            TaskThreadContext.tx().run(() -> {
+                saleService.saveSaleDown(resp.getSaleDownListList());
+                // 回执
+                updateSaleDownStatus(resp.getSaleDownListList());
+            });
+        }
+    }
+
+    /**
+     * 平台的订单传到卖方ERP之后,修改平台里面的订单的上传状态
+     *
+     * @param saleDownList
+     */
+    private void updateSaleDownStatus(List<SaleDown> saleDownList) throws IOException {
+        String idStr = saleDownList.stream().map(saleDown -> String.valueOf(saleDown.getB2BPuId()))
+                .distinct().collect(Collectors.joining(","));
+        UpdateSaleDownStatusReq.Builder req = UpdateSaleDownStatusReq.newBuilder();
+        req.setIdStr(idStr);
+        UpdateSaleDownStatusResp resp = sdk.order().updateSaleDownStatus(req.build());
+        assertOk(resp.getRespHeader());
+    }
+
+    @TaskMapping(title = "下载直接在平台回复采购订单的记录", fixedDelay = 60000, method = Method.DOWNLOAD)
+    public void getSaleReplyList() throws Exception {
+        GetSaleReplyListReq.Builder req = GetSaleReplyListReq.newBuilder();
+        GetSaleReplyListResp resp = sdk.order().getSaleReplyList(req.build());
+        assertOk(resp.getRespHeader());
+        if (resp.getSaleReplyListCount() > 0) {
+            logger.debug("getSaleReplyList, resp count {}", resp.getSaleReplyListCount());
+            TaskThreadContext.get().setDataSize(resp.getSaleReplyListCount());
+            TaskThreadContext.tx().run(() -> {
+                saleService.saveReplyList(resp.getSaleReplyListList());
+                // 回执
+                updateSaleReplyStatus(resp.getSaleReplyListList());
+            });
+        }
+    }
+
+    /**
+     * 平台的回复记录传到供应商ERP之后,修改平台里面的回复记录的上传状态
+     *
+     * @param saleReplyList
+     */
+    private void updateSaleReplyStatus(List<SaleReply> saleReplyList) throws IOException {
+        String idStr = saleReplyList.stream().map(reply -> String.valueOf(reply.getB2BPrId())).distinct().collect(Collectors.joining(","));
+        UpdateSaleReplyStatusReq.Builder req = UpdateSaleReplyStatusReq.newBuilder();
+        req.setIdStr(idStr);
+        UpdateSaleReplyStatusResp resp = sdk.order().updateSaleReplyStatus(req.build());
+        assertOk(resp.getRespHeader());
+    }
+
+    @TaskMapping(title = "上传SaleDown回复记录到平台", fixedDelay = 60000, method = Method.UPLOAD)
+    public void saleReply() throws IOException {
+        List<SaleReplyPO> replyList = saleService.toUploadReplyList();
+        if (!CollectionUtils.isEmpty(replyList)) {
+            logger.debug("saleReply, req count {}", replyList.size());
+            TaskThreadContext.get().setData(replyList);
+            SaleReplyReq.Builder req = SaleReplyReq.newBuilder();
+            replyList.forEach(reply -> req.addData(reply.map()));
+            SaleReplyResp resp = sdk.order().saleReply(req.build());
+            assertOk(resp.getRespHeader());
+            try {
+                // 修改状态
+                saleService.setReplyUploaded(replyList);
+            } catch (Exception e) {
+                throw new DataConsistencyException(replyList, e);
+            }
+        }
+    }
+
+    @TaskMapping(title = "从平台下载客户下达到平台的结案、反结案采购订单", fixedDelay = 60000, method = Method.DOWNLOAD)
+    public void getSaleDownDetailEnd() throws Exception {
+        GetSaleDownDetailEndReq.Builder req = GetSaleDownDetailEndReq.newBuilder();
+        GetSaleDownDetailEndResp resp = sdk.order().getSaleDownDetailEnd(req.build());
+        assertOk(resp.getRespHeader());
+        if (resp.getDetailEndListCount() > 0) {
+            logger.debug("getSaleDownDetailEnd, resp count {}", resp.getDetailEndListCount());
+            TaskThreadContext.get().setDataSize(resp.getDetailEndListCount());
+            TaskThreadContext.tx().run(() -> {
+                saleService.saveEndList(resp.getDetailEndListList());
+                // 回执
+                updateSaleDownDetailEnd(resp.getDetailEndListList());
+            });
+        }
+    }
+
+    /**
+     * 平台的结案、反结案客户采购单传到供应商ERP之后,修改平台里面的上传状态
+     *
+     * @param endList
+     */
+    private void updateSaleDownDetailEnd(final List<SaleDownDetailEnd> endList) throws IOException {
+        String idStr = endList.stream().map(end -> String.valueOf(end.getB2BPdId())).distinct().collect(Collectors.joining(","));
+        UpdateSaleDownDetailEndReq.Builder req = UpdateSaleDownDetailEndReq.newBuilder();
+        req.setIdStr(idStr);
+        UpdateSaleDownDetailEndResp resp = sdk.order().updateSaleDownDetailEnd(req.build());
+        assertOk(resp.getRespHeader());
+    }
+}

+ 32 - 0
uas-pl-core/pom.xml

@@ -0,0 +1,32 @@
+<?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">
+    <parent>
+        <artifactId>uas-pl-integration</artifactId>
+        <groupId>com.usoftchina.uas</groupId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>uas-pl-core</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-jdbc</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>fastjson</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+        </dependency>
+    </dependencies>
+</project>

+ 72 - 0
uas-pl-core/src/main/java/com/usoftchina/uas/pl/agent/AbstractUasAgent.java

@@ -0,0 +1,72 @@
+package com.usoftchina.uas.pl.agent;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.TypeReference;
+import com.usoftchina.uas.pl.context.MasterHolder;
+import com.usoftchina.uas.pl.dto.Result;
+import com.usoftchina.uas.pl.entity.Master;
+import com.usoftchina.uas.pl.exception.EmptyMasterException;
+import com.usoftchina.uas.pl.utils.HmacUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
+import org.springframework.util.LinkedMultiValueMap;
+import org.springframework.util.MultiValueMap;
+import org.springframework.web.client.RestTemplate;
+
+import java.util.Map;
+
+
+/**
+ * @author Pro1
+ * @date 2017/9/4.
+ */
+public class AbstractUasAgent {
+
+    @Autowired
+    private RestTemplate restTemplate;
+
+    /**
+     * UAS系统地址
+     *
+     * @return
+     */
+    private String getUASUrl() {
+        Master master = MasterHolder.get();
+        if (null == master) {
+            throw new EmptyMasterException();
+        }
+
+        return master.getDataCenter().getErpInnerUrl();
+    }
+
+    /**
+     * 身份签名
+     *
+     * @return
+     */
+    private String getSignature() {
+        Master master = MasterHolder.get();
+        if (null == master) {
+            throw new EmptyMasterException();
+        }
+        String url = "_timestamp=" + System.currentTimeMillis() + "&master=" + master.getMa_name();
+        // 签名
+        return url + "&_signature=" + HmacUtils.encode(url);
+    }
+
+    public boolean postForEntity(String url, Map<String, Object> vars) {
+        HttpHeaders headers = new HttpHeaders();
+        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
+        headers.add("referer", getSignature());
+        MultiValueMap<String, Object> formData = new LinkedMultiValueMap<>();
+        formData.setAll(vars);
+        HttpEntity<MultiValueMap<String, Object>> request = new HttpEntity<>(formData, headers);
+        String returnStr = restTemplate.postForEntity(getUASUrl() + url, request, String.class).getBody();
+        Result<String> wrap = JSON.parseObject(returnStr, new TypeReference<Result<String>>() {
+        });
+        return wrap.isSuccess();
+    }
+
+}

+ 24 - 0
uas-pl-core/src/main/java/com/usoftchina/uas/pl/context/ContextHolder.java

@@ -0,0 +1,24 @@
+package com.usoftchina.uas.pl.context;
+
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author yingp
+ * @date 2019/5/6
+ */
+@Component
+public class ContextHolder implements ApplicationContextAware {
+
+    private static ApplicationContext applicationContext;
+
+    @Override
+    public void setApplicationContext(ApplicationContext applicationContext) {
+        ContextHolder.applicationContext = applicationContext;
+    }
+
+    public static ApplicationContext getApplicationContext() {
+        return applicationContext;
+    }
+}

+ 38 - 0
uas-pl-core/src/main/java/com/usoftchina/uas/pl/context/MasterHolder.java

@@ -0,0 +1,38 @@
+package com.usoftchina.uas.pl.context;
+
+import com.usoftchina.uas.pl.entity.Master;
+
+/**
+ * @author yingp
+ * @date 2020/1/13
+ */
+public class MasterHolder {
+
+    private static final ThreadLocal<Master> threadLocalMaster = new InheritableThreadLocal<>();
+
+    /**
+     * 获取当前Master
+     *
+     * @return
+     */
+    public static Master get() {
+        return threadLocalMaster.get();
+    }
+
+    /**
+     * 切换Master
+     *
+     * @param master
+     */
+    public static void set(Master master) {
+        Master old = get();
+        boolean changed = null == old || !old.equals(master);
+        if (changed) {
+            threadLocalMaster.set(master);
+        }
+    }
+
+    public static void clear() {
+        threadLocalMaster.set(null);
+    }
+}

+ 56 - 0
uas-pl-core/src/main/java/com/usoftchina/uas/pl/controller/MasterController.java

@@ -0,0 +1,56 @@
+package com.usoftchina.uas.pl.controller;
+
+import com.usoftchina.uas.pl.dto.Result;
+import com.usoftchina.uas.pl.entity.DataCenter;
+import com.usoftchina.uas.pl.service.DataCenterService;
+import com.usoftchina.uas.pl.service.MasterService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * @author yingp
+ * @date 2020/1/15
+ */
+@RequestMapping(path = "/api")
+@RestController
+public class MasterController {
+
+    @Autowired
+    private MasterService masterService;
+
+    @Autowired
+    private DataCenterService dataCenterService;
+
+    @GetMapping(path = "/master")
+    public Result getMasterList() {
+        return Result.success(masterService.findAll());
+    }
+
+    /**
+     * 刷新
+     *
+     * @return
+     */
+    @PostMapping(path = "/master/refresh")
+    public Result refreshMasterList() throws Exception {
+        masterService.refreshMasters();
+        return Result.success();
+    }
+
+    @GetMapping(path = "/dc")
+    public Result getDataCenterList() {
+        return Result.success(dataCenterService.findAll());
+    }
+
+    @PostMapping(path = "/dc")
+    public Result saveDataCenter(DataCenter dataCenter) {
+        dataCenterService.save(dataCenter);
+        return Result.success();
+    }
+
+    @DeleteMapping(path = "/dc/{id}")
+    public Result deleteDataCenter(@PathVariable("id") Integer id) {
+        dataCenterService.delete(id);
+        return Result.success();
+    }
+}

+ 40 - 0
uas-pl-core/src/main/java/com/usoftchina/uas/pl/crypto/Hex.java

@@ -0,0 +1,40 @@
+package com.usoftchina.uas.pl.crypto;
+
+public final class Hex {
+	private static final char[] HEX = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
+
+	public static char[] encode(byte[] bytes) {
+		int nBytes = bytes.length;
+		char[] result = new char[2 * nBytes];
+
+		int j = 0;
+		for (int i = 0; i < nBytes; ++i) {
+			result[(j++)] = HEX[((0xF0 & bytes[i]) >>> 4)];
+
+			result[(j++)] = HEX[(0xF & bytes[i])];
+		}
+
+		return result;
+	}
+
+	public static byte[] decode(CharSequence s) {
+		int nChars = s.length();
+
+		if (nChars % 2 != 0) {
+			throw new IllegalArgumentException("Hex-encoded string must have an even number of characters");
+		}
+
+		byte[] result = new byte[nChars / 2];
+
+		for (int i = 0; i < nChars; i += 2) {
+			int msb = Character.digit(s.charAt(i), 16);
+			int lsb = Character.digit(s.charAt(i + 1), 16);
+
+			if ((msb < 0) || (lsb < 0)) {
+				throw new IllegalArgumentException("Non-hex character in input: " + s);
+			}
+			result[(i / 2)] = (byte) (msb << 4 | lsb);
+		}
+		return result;
+	}
+}

+ 97 - 0
uas-pl-core/src/main/java/com/usoftchina/uas/pl/crypto/HmacEncoder.java

@@ -0,0 +1,97 @@
+package com.usoftchina.uas.pl.crypto;
+
+import javax.crypto.KeyGenerator;
+import javax.crypto.Mac;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.SecretKeySpec;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.NoSuchAlgorithmException;
+
+/**
+ * Hash-based message authentication code,利用哈希算法,以一个密钥和一个消息为输入,生成一个消息摘要作为输出
+ * 
+ * @author yingp
+ *
+ */
+public class HmacEncoder {
+
+	private final String algorithm;
+
+	public HmacEncoder(String algorithm) {
+		this.algorithm = algorithm;
+	}
+
+	/**
+	 * 根据给定密钥生成算法创建密钥
+	 * 
+	 * @return 密钥
+	 * @throws RuntimeException
+	 *             当 {@link NoSuchAlgorithmException} 发生时
+	 */
+	public byte[] getKey() {
+		// 初始化KeyGenerator
+		KeyGenerator keyGenerator = null;
+		try {
+			keyGenerator = KeyGenerator.getInstance(algorithm);
+		} catch (NoSuchAlgorithmException e) {
+			throw new RuntimeException(e.getMessage());
+		}
+		// 产生密钥
+		SecretKey secretKey = keyGenerator.generateKey();
+		// 获得密钥
+		return secretKey.getEncoded();
+	}
+
+	/**
+	 * 转换密钥
+	 * 
+	 * @param key
+	 *            二进制密钥
+	 * @param algorithm
+	 *            密钥算法
+	 * @return 密钥
+	 */
+	private static Key toKey(byte[] key, String algorithm) {
+		// 生成密钥
+		return new SecretKeySpec(key, algorithm);
+	}
+
+	/**
+	 * 使用指定消息摘要算法计算消息摘要
+	 * 
+	 * @param data
+	 *            做消息摘要的数据
+	 * @param key
+	 *            密钥
+	 * @return 消息摘要(长度为16的字节数组)
+	 */
+	public byte[] encode(byte[] data, Key key) {
+		Mac mac = null;
+		try {
+			mac = Mac.getInstance(algorithm);
+			mac.init(key);
+		} catch (NoSuchAlgorithmException e) {
+			e.printStackTrace();
+			return new byte[0];
+		} catch (InvalidKeyException e) {
+			e.printStackTrace();
+			return new byte[0];
+		}
+		return mac.doFinal(data);
+	}
+
+	/**
+	 * 使用指定消息摘要算法计算消息摘要
+	 * 
+	 * @param data
+	 *            做消息摘要的数据
+	 * @param key
+	 *            密钥
+	 * @return 消息摘要(长度为16的字节数组)
+	 */
+	public byte[] encode(byte[] data, byte[] key) {
+		return encode(data, toKey(key, algorithm));
+	}
+
+}

+ 9 - 0
uas-pl-core/src/main/java/com/usoftchina/uas/pl/crypto/HmacSHA256Encoder.java

@@ -0,0 +1,9 @@
+package com.usoftchina.uas.pl.crypto;
+
+public class HmacSHA256Encoder extends HmacEncoder {
+
+	public HmacSHA256Encoder() {
+		super("HmacSHA256");
+	}
+
+}

+ 23 - 0
uas-pl-core/src/main/java/com/usoftchina/uas/pl/dto/PageDefault.java

@@ -0,0 +1,23 @@
+package com.usoftchina.uas.pl.dto;
+
+import java.lang.annotation.*;
+
+/**
+ * 默认分页参数
+ *
+ * @author yingp
+ * @date 2018/11/7
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.PARAMETER)
+public @interface PageDefault {
+    /**
+     * 页码
+     */
+    int number() default 1;
+    /**
+     * 每页条数
+     */
+    int size() default 20;
+}

+ 54 - 0
uas-pl-core/src/main/java/com/usoftchina/uas/pl/dto/PageRequest.java

@@ -0,0 +1,54 @@
+package com.usoftchina.uas.pl.dto;
+
+import java.io.Serializable;
+
+/**
+ * @author yingp
+ * @date 2018/10/9
+ */
+public class PageRequest implements Serializable{
+    /**
+     * 页码
+     */
+    private int number;
+    /**
+     * 每页条数
+     */
+    private int size;
+
+    public PageRequest() {
+    }
+
+    public PageRequest(int number, int size) {
+        this.number = number;
+        this.size = size;
+    }
+
+    public static PageRequest of(int number, int size) {
+        return new PageRequest(number, size);
+    }
+
+    public int getNumber() {
+        return number;
+    }
+
+    public void setNumber(int number) {
+        this.number = number;
+    }
+
+    public int getSize() {
+        return size;
+    }
+
+    public void setSize(int size) {
+        this.size = size;
+    }
+
+    public int start() {
+        return (number - 1) * size + 1;
+    }
+
+    public int end() {
+        return number * size;
+    }
+}

+ 94 - 0
uas-pl-core/src/main/java/com/usoftchina/uas/pl/dto/PageRequestArgumentResolver.java

@@ -0,0 +1,94 @@
+package com.usoftchina.uas.pl.dto;
+
+import org.springframework.core.MethodParameter;
+import org.springframework.lang.Nullable;
+import org.springframework.util.StringUtils;
+import org.springframework.web.bind.support.WebDataBinderFactory;
+import org.springframework.web.context.request.NativeWebRequest;
+import org.springframework.web.method.support.HandlerMethodArgumentResolver;
+import org.springframework.web.method.support.ModelAndViewContainer;
+
+import java.util.Optional;
+
+/**
+ * 分页参数处理器,设置分页默认参数
+ *
+ * @author yingp
+ * @date 2018/11/7
+ */
+public class PageRequestArgumentResolver implements HandlerMethodArgumentResolver {
+
+    static final PageRequest DEFAULT_PAGE_REQUEST = PageRequest.of(1, 20);
+
+    private PageRequest fallbackPageable = DEFAULT_PAGE_REQUEST;
+
+    private static final int DEFAULT_MAX_PAGE_SIZE = 2000;
+
+    private int maxPageSize = DEFAULT_MAX_PAGE_SIZE;
+
+    @Nullable
+    @Override
+    public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
+        PageRequest defaultOrFallback = getDefaultFromAnnotationOrFallback(parameter);
+
+        Optional<Integer> pageNumber = parseAndApplyBoundaries(webRequest.getParameter("number"),
+                Integer.MAX_VALUE);
+        Optional<Integer> pageSize = parseAndApplyBoundaries(webRequest.getParameter("size"),
+                maxPageSize);
+
+        int pn = pageNumber.orElseGet(defaultOrFallback::getNumber);
+        int ps = pageSize.orElseGet(defaultOrFallback::getSize);
+
+        return PageRequest.of(pn, ps);
+    }
+
+    @Override
+    public boolean supportsParameter(MethodParameter parameter) {
+        return parameter.hasParameterAnnotation(PageDefault.class);
+    }
+
+    private PageRequest getDefaultFromAnnotationOrFallback(MethodParameter parameter) {
+        PageDefault pageDefault = parameter.getParameterAnnotation(PageDefault.class);
+        if (pageDefault != null) {
+            return getDefaultPageRequestFrom(parameter, pageDefault);
+        }
+        return fallbackPageable;
+    }
+
+    private static PageRequest getDefaultPageRequestFrom(MethodParameter parameter, PageDefault pageDefault) {
+        Integer defaultPageNumber = pageDefault.number();
+        Integer defaultPageSize = pageDefault.size();
+
+        if (defaultPageNumber < 1 || defaultPageSize < 1) {
+            throw new RuntimeException("invalid default page");
+        }
+
+        return new PageRequest(defaultPageNumber, defaultPageSize);
+    }
+
+    /**
+     * Tries to parse the given {@link String} into an integer and applies the given boundaries. Will return 0 if the
+     * {@link String} cannot be parsed.
+     *
+     * @param parameter the parameter value.
+     * @param upper     the upper bound to be applied.
+     * @return
+     */
+    private Optional<Integer> parseAndApplyBoundaries(@Nullable String parameter, int upper) {
+
+        if (!StringUtils.hasText(parameter)) {
+            return Optional.empty();
+        }
+
+        try {
+            int parsed = Integer.parseInt(parameter);
+            return Optional.of(parsed < 0 ? 0 : parsed > upper ? upper : parsed);
+        } catch (NumberFormatException e) {
+            return Optional.of(0);
+        }
+    }
+
+    public void setMaxPageSize(int maxPageSize) {
+        this.maxPageSize = maxPageSize;
+    }
+}

+ 33 - 0
uas-pl-core/src/main/java/com/usoftchina/uas/pl/dto/Paging.java

@@ -0,0 +1,33 @@
+package com.usoftchina.uas.pl.dto;
+
+import java.util.List;
+
+/**
+ * @author yingp
+ * @date 2020/1/16
+ */
+public class Paging<T> {
+    private List<T> content;
+    private int totalSize;
+
+    public Paging(List<T> content, int totalSize) {
+        this.content = content;
+        this.totalSize = totalSize;
+    }
+
+    public List<T> getContent() {
+        return content;
+    }
+
+    public void setContent(List<T> content) {
+        this.content = content;
+    }
+
+    public int getTotalSize() {
+        return totalSize;
+    }
+
+    public void setTotalSize(int totalSize) {
+        this.totalSize = totalSize;
+    }
+}

+ 120 - 0
uas-pl-core/src/main/java/com/usoftchina/uas/pl/dto/Result.java

@@ -0,0 +1,120 @@
+package com.usoftchina.uas.pl.dto;
+
+import com.alibaba.fastjson.JSON;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.PrintWriter;
+
+/**
+ * @author Pro1
+ * @date 2017/6/23.
+ */
+public class Result<T> {
+
+    private boolean success;
+
+    private Integer code;
+
+    private String message;
+
+    private T content;
+
+    public boolean isSuccess() {
+        return success;
+    }
+
+    public void setSuccess(boolean success) {
+        this.success = success;
+    }
+
+    public Integer getCode() {
+        return code;
+    }
+
+    public void setCode(Integer code) {
+        this.code = code;
+    }
+
+    public T getContent() {
+        return content;
+    }
+
+    public void setContent(T content) {
+        this.content = content;
+    }
+
+    public String getMessage() {
+        return message;
+    }
+
+    public void setMessage(String message) {
+        this.message = message;
+    }
+
+    public static Result success() {
+        Result result = new Result();
+        result.setSuccess(true);
+        return result;
+    }
+
+    public static <T> Result success(T data) {
+        Result<T> result = success();
+        result.setContent(data);
+        return result;
+    }
+
+    public static Result error() {
+        Result result = new Result();
+        result.setSuccess(false);
+        return result;
+    }
+
+    public static Result error(String message) {
+        Result result = error();
+        result.setMessage(message);
+        return result;
+    }
+
+    public static Result error(int code, String message) {
+        Result result = error();
+        result.setCode(code);
+        result.setMessage(message);
+        return result;
+    }
+
+    public static Result error(int code, String message, Object... args) {
+        Result result = error();
+        result.setCode(code);
+        result.setMessage(String.format(message, args));
+        return result;
+    }
+
+    public static <T> void success(HttpServletResponse response, T data) throws IOException {
+        response.setStatus(HttpStatus.OK.value());
+        response.setContentType(MediaType.APPLICATION_JSON_UTF8.toString());
+        PrintWriter printWriter = response.getWriter();
+        printWriter.append(JSON.toJSONString(success(data)));
+        printWriter.flush();
+        printWriter.close();
+    }
+
+    public static <T> void error(HttpServletResponse response, int code, String message) throws IOException{
+        response.setStatus(HttpStatus.OK.value());
+        response.setContentType(MediaType.APPLICATION_JSON_UTF8.toString());
+        PrintWriter printWriter = response.getWriter();
+        printWriter.append(JSON.toJSONString(error(code, message)));
+        printWriter.flush();
+        printWriter.close();
+    }
+
+    public static <T> void error(HttpServletResponse response, String message) throws IOException {
+        error(response, HttpStatus.BAD_REQUEST.value(), message);
+    }
+
+    public static <T> void error(HttpServletResponse response) throws IOException {
+        error(response, HttpStatus.BAD_REQUEST.value(), null);
+    }
+}

+ 86 - 0
uas-pl-core/src/main/java/com/usoftchina/uas/pl/entity/DataCenter.java

@@ -0,0 +1,86 @@
+package com.usoftchina.uas.pl.entity;
+
+import com.usoftchina.uas.pl.jdbc.DataSourceBean;
+import com.usoftchina.uas.pl.utils.StringUtils;
+
+/**
+ * @author yingp
+ * @date 2020/1/15
+ */
+public class DataCenter implements DataSourceBean {
+
+    private Integer id;
+    private String url;
+    private String username;
+    private String password;
+    private String driverClassName;
+    private String erpInnerUrl;
+
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    public String getUrl() {
+        return url;
+    }
+
+    public void setUrl(String url) {
+        this.url = url;
+    }
+
+    public String getUsername() {
+        return username;
+    }
+
+    public void setUsername(String username) {
+        this.username = username;
+    }
+
+    public String getPassword() {
+        return password;
+    }
+
+    public void setPassword(String password) {
+        this.password = password;
+    }
+
+    public String getDriverClassName() {
+        return driverClassName;
+    }
+
+    public void setDriverClassName(String driverClassName) {
+        this.driverClassName = driverClassName;
+    }
+
+    public String getErpInnerUrl() {
+        return erpInnerUrl;
+    }
+
+    public void setErpInnerUrl(String erpInnerUrl) {
+        this.erpInnerUrl = erpInnerUrl;
+    }
+
+    @Override
+    public String url() {
+        return url;
+    }
+
+    @Override
+    public String username() {
+        return username;
+    }
+
+    @Override
+    public String password() {
+        return password;
+    }
+
+    @Override
+    public String driverClassName() {
+        return StringUtils.nvl(driverClassName, "oracle.jdbc.OracleDriver");
+    }
+}

+ 14 - 0
uas-pl-core/src/main/java/com/usoftchina/uas/pl/entity/KeyEntity.java

@@ -0,0 +1,14 @@
+package com.usoftchina.uas.pl.entity;
+
+/**
+ * @author yingp
+ * @date 2020/1/16
+ */
+public interface KeyEntity {
+    /**
+     * id
+     *
+     * @return
+     */
+    Object id();
+}

+ 194 - 0
uas-pl-core/src/main/java/com/usoftchina/uas/pl/entity/Master.java

@@ -0,0 +1,194 @@
+package com.usoftchina.uas.pl.entity;
+
+import com.usoftchina.uas.pl.jdbc.DataSourceBean;
+import com.usoftchina.uas.pl.utils.StringUtils;
+
+/**
+ * Created by Pro1 on 2017/7/26.
+ */
+public class Master implements DataSourceBean {
+
+    private int ma_id;
+    private String ma_user;// 数据库用户名
+    private String ms_pwd;// 数据库密码
+    private String ma_name;// 帐套名,与bean名一致
+    private String ma_function;
+    private String ma_accesssecret;// 密钥
+    private Short ma_enable;// 是否可使用
+    private Long ma_uu;// 企业UU
+    private Integer ma_b2benable;// 是否启用B2B,1启用,0未启用
+    private String ma_env;// 对应商城环境
+    private String ma_url;
+    private String ma_driver;
+
+    private DataCenter dataCenter;
+
+    public int getMa_id() {
+        return ma_id;
+    }
+
+    public void setMa_id(int ma_id) {
+        this.ma_id = ma_id;
+    }
+
+    public String getMa_user() {
+        return ma_user;
+    }
+
+    public void setMa_user(String ma_user) {
+        this.ma_user = ma_user;
+    }
+
+    public String getMs_pwd() {
+        return ms_pwd;
+    }
+
+    public void setMs_pwd(String ms_pwd) {
+        this.ms_pwd = ms_pwd;
+    }
+
+    public String getMa_name() {
+        return ma_name;
+    }
+
+    public void setMa_name(String ma_name) {
+        this.ma_name = ma_name;
+    }
+
+    public Long getMa_uu() {
+        return ma_uu;
+    }
+
+    public void setMa_uu(Long ma_uu) {
+        this.ma_uu = ma_uu;
+    }
+
+    public String getMa_function() {
+        return ma_function;
+    }
+
+    public void setMa_function(String ma_function) {
+        this.ma_function = ma_function;
+    }
+
+    public String getMa_accesssecret() {
+        return ma_accesssecret;
+    }
+
+    public void setMa_accesssecret(String ma_accesssecret) {
+        this.ma_accesssecret = ma_accesssecret;
+    }
+
+    public Short getMa_enable() {
+        return ma_enable;
+    }
+
+    public void setMa_enable(Short ma_enable) {
+        this.ma_enable = ma_enable;
+    }
+
+    public Integer getMa_b2benable() {
+        return ma_b2benable;
+    }
+
+    public void setMa_b2benable(Integer ma_b2benable) {
+        this.ma_b2benable = ma_b2benable;
+    }
+
+    public String getMa_env() {
+        return ma_env;
+    }
+
+    public void setMa_env(String ma_env) {
+        this.ma_env = ma_env;
+    }
+
+    public String getEnv() {
+        return StringUtils.nvl(this.getMa_env(), "test");
+    }
+
+    public boolean wasTest() {
+        return "test".equals(getEnv());
+    }
+
+    public String getMa_url() {
+        return ma_url;
+    }
+
+    public void setMa_url(String ma_url) {
+        this.ma_url = ma_url;
+    }
+
+    public String getMa_driver() {
+        return ma_driver;
+    }
+
+    public void setMa_driver(String ma_driver) {
+        this.ma_driver = ma_driver;
+    }
+
+    public DataCenter getDataCenter() {
+        return dataCenter;
+    }
+
+    public void setDataCenter(DataCenter dataCenter) {
+        this.dataCenter = dataCenter;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        Master master = (Master) o;
+
+        if (ma_id != master.ma_id) return false;
+        if (ma_user != null ? !ma_user.equals(master.ma_user) : master.ma_user != null) return false;
+        if (ms_pwd != null ? !ms_pwd.equals(master.ms_pwd) : master.ms_pwd != null) return false;
+        if (ma_name != null ? !ma_name.equals(master.ma_name) : master.ma_name != null) return false;
+        if (ma_function != null ? !ma_function.equals(master.ma_function) : master.ma_function != null) return false;
+        if (ma_accesssecret != null ? !ma_accesssecret.equals(master.ma_accesssecret) : master.ma_accesssecret != null)
+            return false;
+        if (ma_enable != null ? !ma_enable.equals(master.ma_enable) : master.ma_enable != null) return false;
+        if (ma_uu != null ? !ma_uu.equals(master.ma_uu) : master.ma_uu != null) return false;
+        if (ma_b2benable != null ? !ma_b2benable.equals(master.ma_b2benable) : master.ma_b2benable != null)
+            return false;
+        return ma_env != null ? ma_env.equals(master.ma_env) : master.ma_env == null;
+
+    }
+
+    @Override
+    public int hashCode() {
+        int result = ma_id;
+        result = 31 * result + (ma_user != null ? ma_user.hashCode() : 0);
+        result = 31 * result + (ms_pwd != null ? ms_pwd.hashCode() : 0);
+        result = 31 * result + (ma_name != null ? ma_name.hashCode() : 0);
+        result = 31 * result + (ma_function != null ? ma_function.hashCode() : 0);
+        result = 31 * result + (ma_accesssecret != null ? ma_accesssecret.hashCode() : 0);
+        result = 31 * result + (ma_enable != null ? ma_enable.hashCode() : 0);
+        result = 31 * result + (ma_uu != null ? ma_uu.hashCode() : 0);
+        result = 31 * result + (ma_b2benable != null ? ma_b2benable.hashCode() : 0);
+        result = 31 * result + (ma_env != null ? ma_env.hashCode() : 0);
+        return result;
+    }
+
+    @Override
+    public String url() {
+        return ma_url;
+    }
+
+    @Override
+    public String username() {
+        return ma_user.toUpperCase();
+    }
+
+    @Override
+    public String password() {
+        return ms_pwd;
+    }
+
+    @Override
+    public String driverClassName() {
+        return StringUtils.nvl(ma_driver, "oracle.jdbc.OracleDriver");
+    }
+}

+ 46 - 0
uas-pl-core/src/main/java/com/usoftchina/uas/pl/event/DataCenterEvents.java

@@ -0,0 +1,46 @@
+package com.usoftchina.uas.pl.event;
+
+import com.usoftchina.uas.pl.entity.DataCenter;
+import org.springframework.context.ApplicationEvent;
+
+/**
+ * @author yingp
+ * @date 2020/1/15
+ */
+public class DataCenterEvents {
+
+    public static class Added extends DataCenterEvent {
+
+        public Added(Object source, DataCenter dataCenter) {
+            super(source, dataCenter);
+        }
+    }
+
+    public static class Modified extends DataCenterEvent {
+
+        public Modified(Object source, DataCenter dataCenter) {
+            super(source, dataCenter);
+        }
+    }
+
+    public static class Removed extends DataCenterEvent {
+
+        public Removed(Object source, DataCenter dataCenter) {
+            super(source, dataCenter);
+        }
+    }
+
+    private abstract static class DataCenterEvent extends ApplicationEvent {
+
+        private final DataCenter dataCenter;
+
+        public DataCenterEvent(Object source, DataCenter dataCenter) {
+            super(source);
+            this.dataCenter = dataCenter;
+        }
+
+        public DataCenter getDataCenter() {
+            return dataCenter;
+        }
+    }
+}

+ 23 - 0
uas-pl-core/src/main/java/com/usoftchina/uas/pl/event/MasterChangedEvent.java

@@ -0,0 +1,23 @@
+package com.usoftchina.uas.pl.event;
+
+import com.usoftchina.uas.pl.entity.Master;
+import org.springframework.context.ApplicationEvent;
+
+import java.util.List;
+
+/**
+ * @author yingp
+ * @date 2020/1/15
+ */
+public class MasterChangedEvent extends ApplicationEvent {
+    private final List<Master> masterList;
+
+    public MasterChangedEvent(Object source, List<Master> masterList) {
+        super(source);
+        this.masterList = masterList;
+    }
+
+    public List<Master> getMasterList() {
+        return masterList;
+    }
+}

+ 8 - 0
uas-pl-core/src/main/java/com/usoftchina/uas/pl/exception/EmptyMasterException.java

@@ -0,0 +1,8 @@
+package com.usoftchina.uas.pl.exception;
+
+/**
+ * @author yingp
+ * @date 2020/1/15
+ */
+public class EmptyMasterException extends RuntimeException {
+}

+ 46 - 0
uas-pl-core/src/main/java/com/usoftchina/uas/pl/jdbc/DataSourceBean.java

@@ -0,0 +1,46 @@
+package com.usoftchina.uas.pl.jdbc;
+
+/**
+ * 数据源配置
+ *
+ * @author yingp
+ * @date 2019/5/23
+ */
+public interface DataSourceBean {
+    /**
+     * jdbc url
+     *
+     * @return
+     */
+    String url();
+
+    /**
+     * 用户
+     *
+     * @return
+     */
+    String username();
+
+    /**
+     * 密码
+     *
+     * @return
+     */
+    String password();
+
+    /**
+     * 驱动
+     *
+     * @return
+     */
+    String driverClassName();
+
+    /**
+     * 连接信息
+     *
+     * @return
+     */
+    default String info() {
+        return "datasource{url: " + url() + ", username: " + username() + "}";
+    }
+}

+ 36 - 0
uas-pl-core/src/main/java/com/usoftchina/uas/pl/jdbc/DataSourceHolder.java

@@ -0,0 +1,36 @@
+package com.usoftchina.uas.pl.jdbc;
+
+/**
+ * @author yingp
+ * @date 2019/5/23
+ */
+public abstract class DataSourceHolder {
+
+    private static final ThreadLocal<DataSourceBean> threadLocalBean = new InheritableThreadLocal<>();
+
+    /**
+     * 获取当前数据源
+     *
+     * @return
+     */
+    public static DataSourceBean get() {
+        return threadLocalBean.get();
+    }
+
+    /**
+     * 切换到新数据源
+     *
+     * @param bean
+     */
+    public static void set(DataSourceBean bean) {
+        DataSourceBean old = get();
+        boolean changed = null == old || !old.equals(bean);
+        if (changed) {
+            threadLocalBean.set(bean);
+        }
+    }
+
+    public static void clear() {
+        threadLocalBean.set(null);
+    }
+}

+ 162 - 0
uas-pl-core/src/main/java/com/usoftchina/uas/pl/jdbc/DynamicDataSource.java

@@ -0,0 +1,162 @@
+package com.usoftchina.uas.pl.jdbc;
+
+import com.usoftchina.uas.pl.utils.StringUtils;
+import com.zaxxer.hikari.HikariDataSource;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.jdbc.datasource.AbstractDataSource;
+import org.springframework.jdbc.datasource.lookup.DataSourceLookup;
+import org.springframework.jdbc.datasource.lookup.JndiDataSourceLookup;
+import org.springframework.util.Assert;
+
+import javax.sql.DataSource;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * 基于{@AbstractRoutingDataSource},解决不能动态添加新数据源的问题
+ *
+ * @author yingp
+ * @date 2017/7/27
+ */
+public class DynamicDataSource extends AbstractDataSource implements InitializingBean {
+
+    private Map<Object, Object> targetDataSources;
+    private Object defaultTargetDataSource;
+    private boolean lenientFallback = true;
+    private DataSourceLookup dataSourceLookup = new JndiDataSourceLookup();
+    private Map<Object, DataSource> resolvedDataSources;
+    private DataSource resolvedDefaultDataSource;
+
+    public void setTargetDataSources(Map<Object, Object> targetDataSources) {
+        this.targetDataSources = targetDataSources;
+    }
+
+    public void setDefaultTargetDataSource(Object defaultTargetDataSource) {
+        this.defaultTargetDataSource = defaultTargetDataSource;
+    }
+
+    public void setLenientFallback(boolean lenientFallback) {
+        this.lenientFallback = lenientFallback;
+    }
+
+    public void setDataSourceLookup(DataSourceLookup dataSourceLookup) {
+        this.dataSourceLookup = (DataSourceLookup) (dataSourceLookup != null ? dataSourceLookup : new JndiDataSourceLookup());
+    }
+
+    @Override
+    public void afterPropertiesSet() {
+        if (this.targetDataSources == null) {
+            throw new IllegalArgumentException("Property \'targetDataSources\' is required");
+        } else {
+            this.resolvedDataSources = new HashMap(this.targetDataSources.size());
+            Iterator var1 = this.targetDataSources.entrySet().iterator();
+
+            while (var1.hasNext()) {
+                Map.Entry entry = (Map.Entry) var1.next();
+                Object lookupKey = this.resolveSpecifiedLookupKey(entry.getKey());
+                DataSource dataSource = this.resolveSpecifiedDataSource(entry.getValue());
+                this.resolvedDataSources.put(lookupKey, dataSource);
+            }
+
+            if (this.defaultTargetDataSource != null) {
+                this.resolvedDefaultDataSource = this.resolveSpecifiedDataSource(this.defaultTargetDataSource);
+            }
+
+        }
+    }
+
+    protected Object resolveSpecifiedLookupKey(Object lookupKey) {
+        return lookupKey;
+    }
+
+    protected DataSource resolveSpecifiedDataSource(Object dataSource) throws IllegalArgumentException {
+        if (dataSource instanceof DataSource) {
+            return (DataSource) dataSource;
+        } else if (dataSource instanceof String) {
+            return this.dataSourceLookup.getDataSource((String) dataSource);
+        } else {
+            throw new IllegalArgumentException("Illegal data source value - only [javax.sql.DataSource] and String supported: " + dataSource);
+        }
+    }
+
+    @Override
+    public Connection getConnection() throws SQLException {
+        return this.determineTargetDataSource().getConnection();
+    }
+
+    @Override
+    public Connection getConnection(String username, String password) throws SQLException {
+        return this.determineTargetDataSource().getConnection(username, password);
+    }
+
+    public String getDriverClassName() throws SQLException{
+        HikariDataSource dataSource = unwrap(HikariDataSource.class);
+        return dataSource.getDriverClassName();
+    }
+
+    public String getJdbcUrl() throws SQLException {
+        HikariDataSource dataSource = unwrap(HikariDataSource.class);
+        return dataSource.getJdbcUrl();
+    }
+
+    public String lookupSchema() throws SQLException{
+        HikariDataSource dataSource = unwrap(HikariDataSource.class);
+        return StringUtils.nvl(dataSource.getSchema(), dataSource.getUsername()).toUpperCase();
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public <T> T unwrap(Class<T> iface) throws SQLException {
+        if (iface.isInstance(this)) {
+            return (T) this;
+        }
+        return determineTargetDataSource().unwrap(iface);
+    }
+
+    @Override
+    public boolean isWrapperFor(Class<?> iface) throws SQLException {
+        return (iface.isInstance(this) || determineTargetDataSource().isWrapperFor(iface));
+    }
+
+    protected DataSource determineTargetDataSource() {
+        Assert.notNull(this.resolvedDataSources, "DataSource router not initialized");
+        Object lookupKey = this.determineCurrentLookupKey();
+        DataSource dataSource = (DataSource) this.resolvedDataSources.get(lookupKey);
+        if (dataSource == null && (this.lenientFallback || lookupKey == null)) {
+            dataSource = this.resolvedDefaultDataSource;
+        }
+
+        if (dataSource == null) {
+            throw new IllegalStateException("Cannot determine target DataSource for lookup key [" + lookupKey + "]");
+        } else {
+            return dataSource;
+        }
+    }
+
+    protected Object determineCurrentLookupKey() {
+        return DataSourceHolder.get();
+    }
+
+    public boolean containsDataSource(Object key) {
+        Object lookupKey = this.resolveSpecifiedLookupKey(key);
+        return this.resolvedDataSources.containsKey(lookupKey);
+    }
+
+    public void addDataSource(Object key, Object value) {
+        Object lookupKey = this.resolveSpecifiedLookupKey(key);
+        if (!containsDataSource(lookupKey)) {
+            DataSource dataSource = this.resolveSpecifiedDataSource(value);
+            this.resolvedDataSources.put(lookupKey, dataSource);
+        }
+    }
+
+    public void removeDataSource(Object key) {
+        Object lookupKey = this.resolveSpecifiedLookupKey(key);
+        if (!containsDataSource(lookupKey)) {
+            this.resolvedDataSources.remove(key);
+        }
+    }
+}

+ 81 - 0
uas-pl-core/src/main/java/com/usoftchina/uas/pl/jdbc/DynamicDataSourceConfig.java

@@ -0,0 +1,81 @@
+package com.usoftchina.uas.pl.jdbc;
+
+import com.zaxxer.hikari.HikariDataSource;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Primary;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
+import org.springframework.jdbc.datasource.DataSourceTransactionManager;
+import org.springframework.util.StringUtils;
+
+import javax.sql.DataSource;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author yingp
+ * @date 2018/12/10
+ */
+@Configuration
+@ConditionalOnClass({HikariDataSource.class})
+@ConditionalOnMissingBean({DataSource.class})
+@EnableConfigurationProperties({
+        DataSourceProperties.class
+})
+public class DynamicDataSourceConfig {
+
+    @Autowired
+    private DataSourceProperties properties;
+
+    @Primary
+    @Bean(name = "defaultDataSource")
+    @ConfigurationProperties(
+            prefix = "spring.datasource.primary"
+    )
+    public HikariDataSource defaultDataSource() {
+        HikariDataSource dataSource = properties.initializeDataSourceBuilder().type(HikariDataSource.class).build();
+        if (StringUtils.hasText(properties.getName())) {
+            dataSource.setPoolName(properties.getName());
+        }
+
+        return dataSource;
+    }
+
+    @Bean(name = "dynamicDataSource")
+    public DynamicDataSource dynamicDataSource(@Qualifier("defaultDataSource") DataSource defaultDataSource) {
+        Map<Object, Object> targetDataSources = new HashMap<>(1);
+        targetDataSources.put("defaultDataSource", defaultDataSource);
+        DynamicDataSource dataSource = new DynamicDataSource();
+        dataSource.setDefaultTargetDataSource(defaultDataSource);
+        dataSource.setTargetDataSources(targetDataSources);
+        return dataSource;
+    }
+
+    @Bean
+    public DataSourceTransactionManager transactionManager(@Qualifier("dynamicDataSource") DynamicDataSource dataSource) throws Exception {
+        return new DataSourceTransactionManager(dataSource);
+    }
+
+    @Bean
+    public DynamicDataSourceRegister dataSourceRegister(@Qualifier("dynamicDataSource") DynamicDataSource dataSource) {
+        return new DynamicDataSourceRegister(properties, dataSource);
+    }
+
+    @Bean
+    public JdbcTemplate jdbcTemplate(@Qualifier("dynamicDataSource") DynamicDataSource dataSource) {
+        return new JdbcTemplate(dataSource);
+    }
+
+    @Bean
+    public NamedParameterJdbcTemplate namedParameterJdbcTemplate(@Qualifier("dynamicDataSource") DynamicDataSource dataSource) {
+        return new NamedParameterJdbcTemplate(dataSource);
+    }
+}

+ 46 - 0
uas-pl-core/src/main/java/com/usoftchina/uas/pl/jdbc/DynamicDataSourceRegister.java

@@ -0,0 +1,46 @@
+package com.usoftchina.uas.pl.jdbc;
+
+import com.usoftchina.uas.pl.utils.StringUtils;
+import com.zaxxer.hikari.HikariDataSource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
+import org.springframework.boot.jdbc.DataSourceBuilder;
+
+import java.sql.SQLException;
+
+/**
+ * 数据源动态注册
+ *
+ * @author yingp
+ * @date 2017/7/27
+ */
+public class DynamicDataSourceRegister {
+
+    private DataSourceProperties defaultProperties;
+    private DynamicDataSource dynamicDataSource;
+    private Logger logger = LoggerFactory.getLogger(getClass());
+
+    public DynamicDataSourceRegister(DataSourceProperties defaultProperties, DynamicDataSource dynamicDataSource) {
+        this.defaultProperties = defaultProperties;
+        this.dynamicDataSource = dynamicDataSource;
+    }
+
+    public void register(DataSourceBean bean) throws SQLException {
+        if (!dynamicDataSource.containsDataSource(bean)) {
+            logger.info(bean.info());
+            HikariDataSource dataSource = DataSourceBuilder.create(defaultProperties.getClassLoader())
+                    .type(HikariDataSource.class)
+                    .driverClassName(StringUtils.nvl(bean.driverClassName(), defaultProperties.determineDriverClassName()))
+                    .url(StringUtils.nvl(bean.url(), dynamicDataSource.getJdbcUrl()))
+                    .username(bean.username())
+                    .password(bean.password())
+                    .build();
+            dynamicDataSource.addDataSource(bean, dataSource);
+        }
+    }
+
+    public void unregister(DataSourceBean bean) {
+        dynamicDataSource.removeDataSource(bean);
+    }
+}

+ 306 - 0
uas-pl-core/src/main/java/com/usoftchina/uas/pl/jdbc/SchemaUtils.java

@@ -0,0 +1,306 @@
+package com.usoftchina.uas.pl.jdbc;
+
+import com.usoftchina.uas.pl.utils.StringUtils;
+import org.springframework.jdbc.core.JdbcTemplate;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * @author yingp
+ * @date 2020/1/15
+ */
+public class SchemaUtils {
+
+    public static TableBuilder newTable(String tableName) {
+        return new TableBuilder(tableName);
+    }
+
+    private static boolean isTableExists(String tableName, JdbcTemplate jdbcTemplate) {
+        int count = jdbcTemplate.queryForObject("select count(1) from user_tables where table_name=?",
+                Integer.class, tableName.toUpperCase());
+        return count > 0;
+    }
+
+    public static ColumnBuilder newColumn(String columnName) {
+        return new ColumnBuilder(columnName);
+    }
+
+    private static boolean isColumnExists(String tableName, String columnName, JdbcTemplate jdbcTemplate) {
+        int count = jdbcTemplate.queryForObject("select count(1) from user_tab_cols where table_name=? and column_name=?",
+                Integer.class, tableName.toUpperCase(), columnName.toUpperCase());
+        return count > 0;
+    }
+
+    public static IndexBuilder newIndex(String indexName, String... columns) {
+        return new IndexBuilder(indexName, columns);
+    }
+
+    private static boolean isIndexExists(String tableName, String indexName, JdbcTemplate jdbcTemplate) {
+        int count = jdbcTemplate.queryForObject("select count(1) from user_indexes where table_name=? and index_name=?",
+                Integer.class, tableName.toUpperCase(), indexName.toUpperCase());
+        return count > 0;
+    }
+
+    public static void create(Table table, JdbcTemplate jdbcTemplate) {
+        TableBuilder builder = newTable(table.name);
+        table.getColumns().forEach(column -> {
+            builder.add(newColumn(column.getName())
+                    .type(column.getType())
+                    .notNull(column.isNotNull())
+                    .primaryKey(column.isPrimaryKey()));
+        });
+        if (null != table.getIndices()) {
+            table.getIndices().forEach(index -> {
+                builder.add(newIndex(index.getName(), index.getColumns())
+                        .unique(index.isUnique()));
+            });
+        }
+        builder.create(jdbcTemplate);
+    }
+
+    public static class Table {
+        private String name;
+        private List<Column> columns;
+        private List<Index> indices;
+
+        public String getName() {
+            return name;
+        }
+
+        public void setName(String name) {
+            this.name = name;
+        }
+
+        public List<Column> getColumns() {
+            return columns;
+        }
+
+        public void setColumns(List<Column> columns) {
+            this.columns = columns;
+        }
+
+        public List<Index> getIndices() {
+            return indices;
+        }
+
+        public void setIndices(List<Index> indices) {
+            this.indices = indices;
+        }
+
+        public void create(JdbcTemplate jdbcTemplate) {
+            SchemaUtils.create(this, jdbcTemplate);
+        }
+    }
+
+    private static class TableBuilder {
+        private final String name;
+        private List<ColumnBuilder> columnBuilderList;
+        private List<IndexBuilder> indexBuilderList;
+
+        public TableBuilder(String name) {
+            this.name = name;
+            this.columnBuilderList = new ArrayList<>(1);
+            this.indexBuilderList = new ArrayList<>(0);
+        }
+
+        public TableBuilder add(ColumnBuilder builder) {
+            columnBuilderList.add(builder);
+            return this;
+        }
+
+        public TableBuilder add(IndexBuilder builder) {
+            indexBuilderList.add(builder);
+            return this;
+        }
+
+        public void create(JdbcTemplate jdbcTemplate) {
+            if (isTableExists(name, jdbcTemplate)) {
+                columnBuilderList.forEach(builder -> {
+                    if (isColumnExists(name, builder.name, jdbcTemplate)) {
+                        builder.modify(this, jdbcTemplate);
+                    } else {
+                        builder.add(this, jdbcTemplate);
+                    }
+                });
+            } else {
+                StringBuffer statement = new StringBuffer("create table ");
+                statement.append(name).append(" (");
+                statement.append(columnBuilderList.stream().map(ColumnBuilder::toString).collect(Collectors.joining(",")));
+                statement.append(")");
+                jdbcTemplate.execute(statement.toString());
+            }
+
+            indexBuilderList.forEach(builder -> {
+                if (!isIndexExists(name, builder.name, jdbcTemplate)) {
+                    builder.create(this, jdbcTemplate);
+                }
+            });
+        }
+    }
+
+    private static class Column {
+        private String name;
+        private String type;
+        private boolean notNull;
+        private boolean primaryKey;
+
+        public String getName() {
+            return name;
+        }
+
+        public void setName(String name) {
+            this.name = name;
+        }
+
+        public String getType() {
+            return type;
+        }
+
+        public void setType(String type) {
+            this.type = type;
+        }
+
+        public boolean isNotNull() {
+            return notNull;
+        }
+
+        public void setNotNull(boolean notNull) {
+            this.notNull = notNull;
+        }
+
+        public boolean isPrimaryKey() {
+            return primaryKey;
+        }
+
+        public void setPrimaryKey(boolean primaryKey) {
+            this.primaryKey = primaryKey;
+        }
+    }
+
+    private static class ColumnBuilder {
+        private final String name;
+        private String type;
+        private boolean notNull;
+        private boolean primaryKey;
+
+        public ColumnBuilder(String name) {
+            this.name = name;
+        }
+
+        public ColumnBuilder type(String type) {
+            this.type = type;
+            return this;
+        }
+
+        public ColumnBuilder notNull() {
+            this.notNull = true;
+            return this;
+        }
+
+        public ColumnBuilder notNull(boolean notNull) {
+            this.notNull = notNull;
+            return this;
+        }
+
+        public ColumnBuilder primaryKey() {
+            this.primaryKey = true;
+            return this;
+        }
+
+        public ColumnBuilder primaryKey(boolean primaryKey) {
+            this.primaryKey = primaryKey;
+            return this;
+        }
+
+        private void add(TableBuilder builder, JdbcTemplate jdbcTemplate) {
+            create(builder, jdbcTemplate, false);
+        }
+
+        private void modify(TableBuilder builder, JdbcTemplate jdbcTemplate) {
+            create(builder, jdbcTemplate, true);
+        }
+
+        private void create(TableBuilder builder, JdbcTemplate jdbcTemplate, boolean modify) {
+            StringBuffer statement = new StringBuffer("alter table ");
+            statement.append(builder.name).append(modify ? " modify " : " add ");
+            statement.append(toString());
+            jdbcTemplate.execute(statement.toString());
+        }
+
+        @Override
+        public String toString() {
+            StringBuffer str = new StringBuffer(name).append(" ");
+            str.append(StringUtils.nvl(type, "varchar2(255)"));
+            if (notNull) {
+                str.append(" not null");
+            }
+            if (primaryKey) {
+                str.append(" primary key");
+            }
+            return str.toString();
+        }
+    }
+
+    private static class Index {
+        private String name;
+        private String[] columns;
+        private boolean unique;
+
+        public String getName() {
+            return name;
+        }
+
+        public void setName(String name) {
+            this.name = name;
+        }
+
+        public String[] getColumns() {
+            return columns;
+        }
+
+        public void setColumns(String[] columns) {
+            this.columns = columns;
+        }
+
+        public boolean isUnique() {
+            return unique;
+        }
+
+        public void setUnique(boolean unique) {
+            this.unique = unique;
+        }
+    }
+
+    private static class IndexBuilder {
+        private final String name;
+        private final String[] columns;
+        private boolean unique;
+
+        public IndexBuilder(String name, String... columns) {
+            this.name = name;
+            this.columns = columns;
+        }
+
+        public IndexBuilder unique() {
+            this.unique = true;
+            return this;
+        }
+
+        public IndexBuilder unique(boolean unique) {
+            this.unique = unique;
+            return this;
+        }
+
+        private void create(TableBuilder builder, JdbcTemplate jdbcTemplate) {
+            StringBuffer statement = new StringBuffer("create ");
+            statement.append(unique ? "unique index " : "index ");
+            statement.append(name).append(" on ");
+            statement.append(builder.name).append(" (");
+            statement.append(StringUtils.arrayToCommaDelimitedString(columns));
+            statement.append(")");
+            jdbcTemplate.execute(statement.toString());
+        }
+    }
+}

+ 92 - 0
uas-pl-core/src/main/java/com/usoftchina/uas/pl/jdbc/Transaction.java

@@ -0,0 +1,92 @@
+package com.usoftchina.uas.pl.jdbc;
+
+import com.usoftchina.uas.pl.context.ContextHolder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.jdbc.datasource.DataSourceTransactionManager;
+import org.springframework.transaction.TransactionDefinition;
+import org.springframework.transaction.TransactionStatus;
+import org.springframework.transaction.support.DefaultTransactionDefinition;
+
+/**
+ * @author yingp
+ * @date 2020/1/16
+ */
+public class Transaction {
+    private static DataSourceTransactionManager transactionManager;
+    private static Logger logger = LoggerFactory.getLogger(Transaction.class);
+
+    private static DataSourceTransactionManager getTransactionManager() {
+        if (null == transactionManager) {
+            synchronized (Transaction.class) {
+                if (null == transactionManager) {
+                    transactionManager = ContextHolder.getApplicationContext().getBean(DataSourceTransactionManager.class);
+                }
+            }
+        }
+        return transactionManager;
+    }
+
+    private TransactionStatus status;
+
+    public void start() {
+        if (null != status) {
+            throw new RuntimeException("A transaction already started");
+        }
+        DefaultTransactionDefinition def = new DefaultTransactionDefinition();
+        def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
+        status = getTransactionManager().getTransaction(def);
+    }
+
+    public void commit() {
+        if (null == status) {
+            throw new RuntimeException("No transaction exists");
+        }
+        getTransactionManager().commit(status);
+    }
+
+    public void rollback(Exception e) {
+        if (null == status) {
+            throw new RuntimeException("No transaction exists");
+        }
+        logger.info("transaction rollback on error: " + e.getMessage());
+        getTransactionManager().rollback(status);
+    }
+
+    /**
+     * 将代码块封装在事务里面执行
+     *
+     * @param runnable
+     * @throws Exception
+     */
+    public void run(TransactionRunnable runnable) throws Exception {
+        Exception err = null;
+        try {
+            start();
+            runnable.run();
+        } catch (Exception e) {
+            err = e;
+        } finally {
+            if (null == err) {
+                try {
+                    commit();
+                } catch (Exception e) {
+                    err = e;
+                }
+            }
+            if (null != err) {
+                rollback(err);
+                throw err;
+            }
+        }
+    }
+
+    public interface TransactionRunnable {
+        /**
+         * run
+         *
+         * @throws Exception
+         */
+        void run() throws Exception;
+    }
+}

+ 72 - 0
uas-pl-core/src/main/java/com/usoftchina/uas/pl/service/AbstractService.java

@@ -0,0 +1,72 @@
+package com.usoftchina.uas.pl.service;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.dao.DataAccessException;
+import org.springframework.dao.EmptyResultDataAccessException;
+import org.springframework.jdbc.core.CallableStatementCallback;
+import org.springframework.jdbc.core.CallableStatementCreator;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.jdbc.core.SqlTypeValue;
+import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
+
+import java.sql.CallableStatement;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.Types;
+
+/**
+ * @author yingp
+ * @date 2020/1/13
+ */
+public abstract class AbstractService {
+
+    @Autowired
+    protected JdbcTemplate jdbcTemplate;
+
+    @Autowired
+    protected NamedParameterJdbcTemplate namedJdbcTemplate;
+
+    /**
+     * 生成序列值
+     *
+     * @param sequence 序列名
+     * @return
+     */
+    protected Integer generate(String sequence) {
+        return jdbcTemplate.queryForObject("select " + sequence + ".nextval from dual", Integer.class);
+    }
+
+    protected <T> T queryForObject(String statement, Class<T> targetCls, Object... arguments) {
+        try {
+            return jdbcTemplate.queryForObject(statement, targetCls, arguments);
+        } catch (EmptyResultDataAccessException e) {
+            return null;
+        }
+    }
+
+    /**
+     * 生成流水码
+     *
+     * @param code 规则名称
+     * @param type 规则类型
+     * @return
+     */
+    protected String generateCode(final String code, final int type) {
+        return jdbcTemplate.execute(new CallableStatementCreator() {
+            @Override
+            public CallableStatement createCallableStatement(Connection con) throws SQLException {
+                CallableStatement cs = con.prepareCall("{call Sp_GetMaxNumber(?,?,?)}");
+                cs.setObject(1, code);
+                cs.setObject(2, type);
+                cs.registerOutParameter(3, Types.VARCHAR);
+                return cs;
+            }
+        }, new CallableStatementCallback<String>() {
+            @Override
+            public String doInCallableStatement(CallableStatement cs) throws SQLException, DataAccessException {
+                cs.execute();
+                return cs.getString(3);
+            }
+        });
+    }
+}

+ 47 - 0
uas-pl-core/src/main/java/com/usoftchina/uas/pl/service/DataCenterService.java

@@ -0,0 +1,47 @@
+package com.usoftchina.uas.pl.service;
+
+import com.usoftchina.uas.pl.context.ContextHolder;
+import com.usoftchina.uas.pl.entity.DataCenter;
+import com.usoftchina.uas.pl.event.DataCenterEvents;
+import org.springframework.dao.EmptyResultDataAccessException;
+import org.springframework.jdbc.core.BeanPropertyRowMapper;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * @author yingp
+ * @date 2020/1/15
+ */
+@Service
+public class DataCenterService extends AbstractService {
+
+    public List<DataCenter> findAll() {
+        return jdbcTemplate.query("select * from DataCenter order by id",
+                new BeanPropertyRowMapper<>(DataCenter.class));
+    }
+
+    public void save(DataCenter dataCenter) {
+        if (null != dataCenter.getId()) {
+            jdbcTemplate.update("update DataCenter set url=?,username=?,password=?,driverClassName=?,erpInnerUrl=? where id=?",
+                    dataCenter.getUrl(), dataCenter.getUsername(), dataCenter.getPassword(), dataCenter.getDriverClassName(), dataCenter.getErpInnerUrl(), dataCenter.getId());
+            ContextHolder.getApplicationContext().publishEvent(new DataCenterEvents.Modified(this, dataCenter));
+        } else {
+            jdbcTemplate.update("insert into DataCenter(url,username,password,driverClassName,erpInnerUrl) values (?,?,?,?,?)",
+                    dataCenter.getUrl(), dataCenter.getUsername(), dataCenter.getPassword(), dataCenter.getDriverClassName(), dataCenter.getErpInnerUrl());
+            ContextHolder.getApplicationContext().publishEvent(new DataCenterEvents.Added(this, dataCenter));
+        }
+    }
+
+    public void delete(int id) {
+        try {
+            DataCenter dataCenter = jdbcTemplate.queryForObject("select * from DataCenter where id=?",
+                    new BeanPropertyRowMapper<>(DataCenter.class), id);
+            if (null != dataCenter) {
+                jdbcTemplate.update("delete from DataCenter where id=?", id);
+                ContextHolder.getApplicationContext().publishEvent(new DataCenterEvents.Removed(this, dataCenter));
+            }
+        } catch (EmptyResultDataAccessException e) {
+        }
+    }
+}

+ 113 - 0
uas-pl-core/src/main/java/com/usoftchina/uas/pl/service/MasterService.java

@@ -0,0 +1,113 @@
+package com.usoftchina.uas.pl.service;
+
+import com.alibaba.fastjson.JSON;
+import com.usoftchina.uas.pl.context.ContextHolder;
+import com.usoftchina.uas.pl.entity.DataCenter;
+import com.usoftchina.uas.pl.entity.Master;
+import com.usoftchina.uas.pl.event.DataCenterEvents;
+import com.usoftchina.uas.pl.event.MasterChangedEvent;
+import com.usoftchina.uas.pl.jdbc.DataSourceHolder;
+import com.usoftchina.uas.pl.jdbc.DynamicDataSourceRegister;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.event.EventListener;
+import org.springframework.jdbc.core.BeanPropertyRowMapper;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * @author yingp
+ * @date 2020/1/15
+ */
+@Service
+public class MasterService extends AbstractService {
+
+    @Autowired
+    private DynamicDataSourceRegister dataSourceRegister;
+
+    @Autowired
+    private DataCenterService dataCenterService;
+
+    private List<Master> mastersCache;
+
+    private final Logger logger = LoggerFactory.getLogger(MasterService.class);
+
+    public List<Master> findAll() {
+        return mastersCache;
+    }
+
+    public Master findByName(String name) {
+        if (null != mastersCache) {
+            return mastersCache.stream().filter(master -> master.getMa_user().equalsIgnoreCase(name)).findFirst().orElse(null);
+        }
+        return null;
+    }
+
+    public synchronized void refreshMasters() throws SQLException {
+        logger.debug("start refresh masters");
+        List<Master> allMasterList = null;
+        List<DataCenter> dataCenterList = dataCenterService.findAll();
+        if (!CollectionUtils.isEmpty(dataCenterList)) {
+            allMasterList = new ArrayList<>();
+            try {
+                for (DataCenter dataCenter : dataCenterList) {
+                    dataSourceRegister.register(dataCenter);
+                    DataSourceHolder.set(dataCenter);
+                    List<Master> masterList = jdbcTemplate.query("select * from master where ma_uu is not null and ma_accesssecret is not null and abs(ma_enable)=1 order by ma_id",
+                            new BeanPropertyRowMapper<>(Master.class));
+                    if (!CollectionUtils.isEmpty(masterList)) {
+                        for (Master master : masterList) {
+                            master.setDataCenter(dataCenter);
+                            dataSourceRegister.register(master);
+                        }
+                        allMasterList.addAll(masterList);
+                    }
+                }
+            } finally {
+                DataSourceHolder.clear();
+            }
+        }
+        if (!Objects.equals(mastersCache, allMasterList)) {
+            logger.debug("masters refreshed, current masters: " + JSON.toJSONString(allMasterList));
+            this.mastersCache = allMasterList;
+            ContextHolder.getApplicationContext().publishEvent(new MasterChangedEvent(this, allMasterList));
+        }
+    }
+
+    /**
+     * 每5分钟刷新一次,防账套有变
+     *
+     * @throws Exception
+     */
+    @Scheduled(fixedDelay = 300000)
+    public void scheduledRefresh() throws Exception {
+        refreshMasters();
+    }
+
+    @Async
+    @EventListener(DataCenterEvents.Added.class)
+    public void onDataCenterAdded(DataCenterEvents.Added event) throws Exception {
+        refreshMasters();
+    }
+
+    @Async
+    @EventListener(DataCenterEvents.Modified.class)
+    public void onDataCenterModified(DataCenterEvents.Modified event) throws Exception {
+        refreshMasters();
+    }
+
+    @Async
+    @EventListener(DataCenterEvents.Removed.class)
+    public void onDataCenterRemoved(DataCenterEvents.Removed event) throws Exception {
+        dataSourceRegister.unregister(event.getDataCenter());
+        refreshMasters();
+    }
+}

+ 51 - 0
uas-pl-core/src/main/java/com/usoftchina/uas/pl/service/SchemaService.java

@@ -0,0 +1,51 @@
+package com.usoftchina.uas.pl.service;
+
+import com.alibaba.fastjson.JSON;
+import com.usoftchina.uas.pl.entity.Master;
+import com.usoftchina.uas.pl.jdbc.DataSourceHolder;
+import com.usoftchina.uas.pl.jdbc.SchemaUtils;
+import com.usoftchina.uas.pl.utils.CollectionUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.stereotype.Service;
+import org.springframework.util.StreamUtils;
+
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.util.List;
+
+/**
+ * @author yingp
+ * @date 2020/1/18
+ */
+@Service
+public class SchemaService extends AbstractService {
+
+    private final Logger logger = LoggerFactory.getLogger(SchemaService.class);
+
+    /**
+     * 刷新账套下的表结构
+     *
+     * @param masterList
+     * @throws IOException
+     */
+    public void refreshSchema(List<Master> masterList) throws IOException {
+        if (!CollectionUtils.isEmpty(masterList)) {
+            ClassPathResource resource = new ClassPathResource("erp_schema.json");
+            String schemaJson = StreamUtils.copyToString(resource.getInputStream(), Charset.defaultCharset());
+            List<SchemaUtils.Table> tableList = JSON.parseArray(schemaJson, SchemaUtils.Table.class);
+            if (!CollectionUtils.isEmpty(tableList)) {
+                try {
+                    for (Master master : masterList) {
+                        DataSourceHolder.set(master);
+                        logger.debug("refresh schema for " + master.getMa_user());
+                        tableList.forEach(table -> table.create(jdbcTemplate));
+                    }
+                } finally {
+                    DataSourceHolder.clear();
+                }
+            }
+        }
+    }
+}

+ 8 - 0
uas-pl-core/src/main/java/com/usoftchina/uas/pl/utils/CollectionUtils.java

@@ -0,0 +1,8 @@
+package com.usoftchina.uas.pl.utils;
+
+/**
+ * @author yingp
+ * @date 2020/1/13
+ */
+public class CollectionUtils extends org.springframework.util.CollectionUtils {
+}

+ 26 - 0
uas-pl-core/src/main/java/com/usoftchina/uas/pl/utils/Const.java

@@ -0,0 +1,26 @@
+package com.usoftchina.uas.pl.utils;
+
+/**
+ * @author yingp
+ * @date 2020/1/13
+ */
+public class Const {
+    /**
+     * 数据传输单次大小限制
+     */
+    public static final int DATA_SIZE_LIMIT = 500;
+    /**
+     * 状态
+     */
+    public static final int OK = 0;
+
+    /**
+     * yes / no
+     */
+    public static final int YES = 1;
+
+    /**
+     * yes / no
+     */
+    public static final int NO = 0;
+}

+ 76 - 0
uas-pl-core/src/main/java/com/usoftchina/uas/pl/utils/DateUtils.java

@@ -0,0 +1,76 @@
+package com.usoftchina.uas.pl.utils;
+
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Map;
+import java.util.TimeZone;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.regex.Pattern;
+
+/**
+ * @author yingp
+ * @date 2019/9/11
+ */
+public class DateUtils {
+
+    private final static Map<String, DateFormat> formats = new ConcurrentHashMap<>();
+    private final static Pattern P_YMD = Pattern.compile("\\d{4}-\\d{2}-\\d{2}");
+    private final static Pattern P_YMD_HMS = Pattern.compile("\\d{4}-\\d{2}-\\d{2}\\s\\d{2}:\\d{2}:\\d{2}");
+    private final static Pattern P_YMD_HMS_TZ = Pattern.compile("\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d{3}Z");
+
+    private static DateFormat getFormat(String pattern, TimeZone timeZone) {
+        DateFormat format = formats.get(pattern + "_" + timeZone.getID());
+        if (null == format) {
+            format = new SimpleDateFormat(pattern);
+            format.setTimeZone(timeZone);
+            formats.put(pattern + "_" + timeZone.getID(), format);
+        }
+        return format;
+    }
+
+    public static String format(Date date, String pattern) {
+        return getFormat(pattern, TimeZone.getDefault()).format(date);
+    }
+
+    public static String format(String date, String pattern) {
+        return getFormat(pattern, TimeZone.getDefault()).format(parse(date));
+    }
+
+    public static String format(Date date) {
+        return format(date, "yyyy-MM-dd");
+    }
+
+    public static String formatDateTime(Date date) {
+        return format(date, "yyyy-MM-dd HH:mm:ss");
+    }
+
+    public static String formatOracle(Date date) {
+        return "to_date('" + formatDateTime(date) + "','yyyy-MM-dd hh24:mi:ss')";
+    }
+
+    public static String toOracle(String date) {
+        if (P_YMD.matcher(date).matches()) {
+            return "to_date('" + date + "','yyyy-MM-dd')";
+        } else if (P_YMD_HMS.matcher(date).matches()) {
+            return "to_date('" + date + "','yyyy-MM-dd hh24:mi:ss')";
+        }
+        return null;
+    }
+
+    public static Date parse(String date) {
+        try {
+            if (P_YMD.matcher(date).matches()) {
+                return getFormat("yyyy-MM-dd", TimeZone.getDefault()).parse(date);
+            } else if (P_YMD_HMS.matcher(date).matches()) {
+                return getFormat("yyyy-MM-dd HH:mm:ss", TimeZone.getDefault()).parse(date);
+            } else if (P_YMD_HMS_TZ.matcher(date).matches()) {
+                return getFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", TimeZone.getTimeZone("UTC")).parse(date);
+            }
+        } catch (ParseException e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+}

+ 50 - 0
uas-pl-core/src/main/java/com/usoftchina/uas/pl/utils/HmacUtils.java

@@ -0,0 +1,50 @@
+package com.usoftchina.uas.pl.utils;
+
+import com.usoftchina.uas.pl.crypto.Hex;
+import com.usoftchina.uas.pl.crypto.HmacEncoder;
+import com.usoftchina.uas.pl.crypto.HmacSHA256Encoder;
+
+/**
+ * Hmac加密工具
+ * 
+ * @author yingp
+ *
+ */
+public class HmacUtils {
+
+	private static HmacEncoder hmacEncoder;
+
+	// 默认约定密钥
+	private final static byte[] key = { 104, 116, 116, 112, 58, 47, 47, 119, 119, 119, 46, 117, 98, 116, 111, 98, 46, 99, 111, 109, 47,
+			101, 114, 112, 47, 115, 97, 108, 101, 47, 111, 114, 100, 101, 114, 115, 63, 115, 111, 109, 101, 116, 104, 105, 110, 103 };
+
+	static {
+		// default algorithm: HmacSHA256
+		hmacEncoder = new HmacSHA256Encoder();
+	}
+
+	/**
+	 * 
+	 * @param message
+	 *            明文
+	 * @return 16进制密文
+	 */
+	public static String encode(Object message) {
+		byte[] encodeData = hmacEncoder.encode(String.valueOf(message).getBytes(), key);
+		return new String(Hex.encode(encodeData));
+	}
+
+	/**
+	 * 
+	 * @param message
+	 *            明文
+	 * @param key
+	 *            密钥
+	 * @return 16进制密文
+	 */
+	public static String encode(Object message, String key) {
+		byte[] encodeData = hmacEncoder.encode(String.valueOf(message).getBytes(), key.getBytes());
+		return new String(Hex.encode(encodeData));
+	}
+
+}

+ 19 - 0
uas-pl-core/src/main/java/com/usoftchina/uas/pl/utils/NumberUtils.java

@@ -0,0 +1,19 @@
+package com.usoftchina.uas.pl.utils;
+
+/**
+ * @author yingp
+ * @date 2019/10/16
+ */
+public class NumberUtils extends org.springframework.util.NumberUtils {
+
+    public static boolean isEmpty(Number number) {
+        return null == number || number.doubleValue() == 0D;
+    }
+
+    public static <T extends Number> T nvl(T value, T emptyValue) {
+        if (null == value) {
+            return emptyValue;
+        }
+        return value;
+    }
+}

+ 137 - 0
uas-pl-core/src/main/java/com/usoftchina/uas/pl/utils/Status.java

@@ -0,0 +1,137 @@
+package com.usoftchina.uas.pl.utils;
+
+/**
+ * 系统业务单据状态
+ * 
+ * @author yingp
+ * 
+ */
+public enum Status {
+
+	/**
+	 * 在录入
+	 */
+	ENTERING("在录入"),
+	/**
+	 * 已提交
+	 */
+	COMMITED("已提交"),
+	/**
+	 * 已审核
+	 */
+	AUDITED("已审核"),
+	/**
+	 * 已冻结
+	 */
+	FREEZE("已冻结"),
+	/**
+	 * 已结案
+	 */
+	FINISH("已结案"),
+	/**
+	 * 已作废
+	 */
+	NULLIFIED("已作废"),
+	/**
+	 * 已过账
+	 */
+	POSTED("已过账"),
+	/**
+	 * 未记账
+	 */
+	UNPOST("未记账"),
+	/**
+	 * 已打印
+	 */
+	PRINTED("已打印"),
+	/**
+	 * 未打印
+	 */
+	UNPRINT("未打印"),
+	/**
+	 * 已回复
+	 */
+	REPLYED("已回复"),
+	/**
+	 * 未回复
+	 */
+	UNREPLY("未回复"),
+	/**
+	 * 未完工
+	 */
+	UNCOMPLET("未完工"),
+	/**
+	 * 挂起
+	 */
+	HUNG("挂起"),
+	/**
+	 * 已禁用
+	 */
+	DISABLE("已禁用"),
+	/**
+	 * 已批准
+	 */
+	APPROVE("已批准"),
+	/**
+	 * 未批准
+	 */
+	UNAPPROVED("未批准"),
+	/**
+	 * 已入库
+	 */
+	TURNIN("已入库"),
+	/**
+	 * 已出库
+	 */
+	TURNOUT("已出库"),
+	/**
+	 * 部分转采购
+	 */
+	PART2PU("部分转采购"),
+	/**
+	 * 已转采购
+	 */
+	TURNPURC("已转采购"),
+	/**
+	 * 已转通知单
+	 */
+	TURNSN("已转通知单"),
+	/**
+	 * 已转收料
+	 */
+	TURNVA("已转收料"),
+	/**
+	 * 待确认
+	 */
+	TO_CONFIRM("待确认"),
+	/**
+	 * 已确认
+	 */
+	CONFIRMED("已确认"),
+	/**
+	 * 空状态
+	 */
+	NONE("");
+
+	private final String code;
+	private final String display;
+
+	private Status(String display) {
+		this.code = this.toString();
+		this.display = display;
+	}
+
+	/**
+	 * @return 状态的编码
+	 */
+	public String code() {
+		if (this == NONE)
+			return "";
+		return this.code;
+	}
+
+	public String display() {
+		return this.display;
+	}
+
+}

+ 35 - 0
uas-pl-core/src/main/java/com/usoftchina/uas/pl/utils/StringUtils.java

@@ -0,0 +1,35 @@
+package com.usoftchina.uas.pl.utils;
+
+/**
+ * @author yingp
+ * @date 2019/5/8
+ */
+public abstract class StringUtils extends org.springframework.util.StringUtils {
+
+    public static String nvl(Object object, String nvlValue) {
+        return isEmpty(object) ? nvlValue : object.toString();
+    }
+
+    public static String nvl(Object object) {
+        return nvl(object, null);
+    }
+
+    /**
+     * 截取字符串
+     *
+     * @param str
+     * @param beginIndex
+     * @param endIndex
+     * @return
+     */
+    public static String substr(String str, int beginIndex, int endIndex) {
+        if (null == str) {
+            return null;
+        }
+        int maxIndex = str.length();
+        if (endIndex > maxIndex) {
+            endIndex = maxIndex;
+        }
+        return str.substring(beginIndex, endIndex);
+    }
+}

+ 22 - 0
uas-pl-finance/pom.xml

@@ -0,0 +1,22 @@
+<?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">
+    <parent>
+        <artifactId>uas-pl-integration</artifactId>
+        <groupId>com.usoftchina.uas</groupId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>uas-pl-finance</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.usoftchina.uas</groupId>
+            <artifactId>uas-pl-task</artifactId>
+        </dependency>
+
+        <!-- TODO finance sdk -->
+    </dependencies>
+</project>

+ 24 - 0
uas-pl-product/pom.xml

@@ -0,0 +1,24 @@
+<?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">
+    <parent>
+        <artifactId>uas-pl-integration</artifactId>
+        <groupId>com.usoftchina.uas</groupId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>uas-pl-product</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.usoftchina.uas</groupId>
+            <artifactId>uas-pl-task</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.usoft.sdk</groupId>
+            <artifactId>usoft-sdk-b2b</artifactId>
+        </dependency>
+    </dependencies>
+</project>

+ 22 - 0
uas-pl-product/src/main/java/com/usoftchina/uas/pl/product/config/ProductConfig.java

@@ -0,0 +1,22 @@
+package com.usoftchina.uas.pl.product.config;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * @author yingp
+ * @date 2020/1/13
+ */
+@Configuration
+@EnableConfigurationProperties(ProductProperties.class)
+public class ProductConfig {
+    @Autowired
+    private ProductProperties properties;
+
+    @Bean
+    public Sdk sdk() {
+        return new Sdk(properties);
+    }
+}

+ 29 - 0
uas-pl-product/src/main/java/com/usoftchina/uas/pl/product/config/ProductProperties.java

@@ -0,0 +1,29 @@
+package com.usoftchina.uas.pl.product.config;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+/**
+ * @author yingp
+ * @date 2020/1/13
+ */
+@ConfigurationProperties(prefix = "product")
+public class ProductProperties {
+    private String url = "http://api-product.usoftchina.com";
+    private String testUrl = "http://test-product.uuzcc.cn";
+
+    public String getUrl() {
+        return url;
+    }
+
+    public void setUrl(String url) {
+        this.url = url;
+    }
+
+    public String getTestUrl() {
+        return testUrl;
+    }
+
+    public void setTestUrl(String testUrl) {
+        this.testUrl = testUrl;
+    }
+}

+ 42 - 0
uas-pl-product/src/main/java/com/usoftchina/uas/pl/product/config/Sdk.java

@@ -0,0 +1,42 @@
+package com.usoftchina.uas.pl.product.config;
+
+import com.usoft.sdk.b2b.client.*;
+import com.usoftchina.uas.pl.context.MasterHolder;
+import com.usoftchina.uas.pl.entity.Master;
+import com.usoftchina.uas.pl.exception.EmptyMasterException;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * sdk封装
+ *
+ * @author yingp
+ * @date 2020/1/13
+ */
+public class Sdk {
+    /**
+     * 物料
+     */
+    private final static Map<Master, ProductSdk> productSdkMap = new ConcurrentHashMap<>();
+    private final ProductProperties properties;
+
+    public Sdk(ProductProperties properties) {
+        this.properties = properties;
+    }
+
+    public ProductSdk instance() {
+        Master master = MasterHolder.get();
+        if (null == master) {
+            throw new EmptyMasterException();
+        }
+        if (!productSdkMap.containsKey(master)) {
+            ProductSdk sdk = new ProductSdk(
+                    master.wasTest() ? properties.getTestUrl() : properties.getUrl(),
+                    String.valueOf(master.getMa_uu()), master.getMa_accesssecret());
+            productSdkMap.put(master, sdk);
+            return sdk;
+        }
+        return productSdkMap.get(master);
+    }
+}

+ 14 - 0
uas-pl-product/src/main/java/com/usoftchina/uas/pl/product/exception/ResponseError.java

@@ -0,0 +1,14 @@
+package com.usoftchina.uas.pl.product.exception;
+
+import com.usoft.b2b.external.api.entity.RespHeader;
+
+/**
+ * @author yingp
+ * @date 2020/1/15
+ */
+public class ResponseError extends RuntimeException{
+
+    public ResponseError(RespHeader header) {
+        super(String.format("code %s, msg: %s", header.getCode(), header.getMsg()));
+    }
+}

+ 244 - 0
uas-pl-product/src/main/java/com/usoftchina/uas/pl/product/po/ProductPO.java

@@ -0,0 +1,244 @@
+package com.usoftchina.uas.pl.product.po;
+
+import com.usoft.b2b.external.erp.product.api.entity.Product;
+import com.usoftchina.uas.pl.context.MasterHolder;
+import com.usoftchina.uas.pl.entity.KeyEntity;
+import com.usoftchina.uas.pl.utils.NumberUtils;
+import com.usoftchina.uas.pl.utils.StringUtils;
+
+/**
+ * ERP系统的产品
+ * 
+ * @author yingp
+ * 
+ */
+public class ProductPO implements KeyEntity {
+
+	private Long pr_id;
+	private String pr_code;
+	private String pr_detail;
+	private String pr_spec;
+	private String pr_unit;
+	private Float pr_zxbzs;
+	private Float pr_zxdhl;
+	private Float pr_leadtime;
+	private Float pr_ltinstock;//备料提前期,天数
+	private String pr_brand;
+	private String pr_orispeccode;// 原厂型号
+	private String pr_uuid; // 标准料号
+	private String pr_status; // 状态: ‘已审核’->有效;‘已禁用’->失效
+	private Short pr_issale; // 可销售
+	private Short pr_ispurchase; // 可采购
+	private Short pr_isshow; // 开放采购物料
+	private Short pr_ispubsale; // 开发销售物料
+	private Long b2b_id;//平台id
+
+	public Long getPr_id() {
+		return pr_id;
+	}
+
+	public void setPr_id(Long pr_id) {
+		this.pr_id = pr_id;
+	}
+
+	public String getPr_code() {
+		return pr_code;
+	}
+
+	public void setPr_code(String pr_code) {
+		this.pr_code = pr_code;
+	}
+
+	public String getPr_detail() {
+		return pr_detail;
+	}
+
+	public void setPr_detail(String pr_detail) {
+		this.pr_detail = pr_detail;
+	}
+
+	public String getPr_spec() {
+		return pr_spec;
+	}
+
+	public void setPr_spec(String pr_spec) {
+		this.pr_spec = pr_spec;
+	}
+
+	public String getPr_unit() {
+		return pr_unit;
+	}
+
+	public void setPr_unit(String pr_unit) {
+		this.pr_unit = pr_unit;
+	}
+
+	public Float getPr_zxbzs() {
+		return pr_zxbzs;
+	}
+
+	public void setPr_zxbzs(Float pr_zxbzs) {
+		this.pr_zxbzs = pr_zxbzs;
+	}
+
+	public Float getPr_zxdhl() {
+		return pr_zxdhl;
+	}
+
+	public void setPr_zxdhl(Float pr_zxdhl) {
+		this.pr_zxdhl = pr_zxdhl;
+	}
+
+	public Float getPr_leadtime() {
+		return pr_leadtime;
+	}
+
+	public void setPr_leadtime(Float pr_leadtime) {
+		this.pr_leadtime = pr_leadtime;
+	}
+
+	public Float getPr_ltinstock() {
+		return pr_ltinstock;
+	}
+
+	public void setPr_ltinstock(Float pr_ltinstock) {
+		this.pr_ltinstock = pr_ltinstock;
+	}
+
+	public String getPr_brand() {
+		return pr_brand;
+	}
+
+	public void setPr_brand(String pr_brand) {
+		this.pr_brand = pr_brand;
+	}
+
+	public String getPr_orispeccode() {
+		return pr_orispeccode;
+	}
+
+	public void setPr_orispeccode(String pr_orispeccode) {
+		this.pr_orispeccode = pr_orispeccode;
+	}
+
+	public String getPr_uuid() {
+		return pr_uuid;
+	}
+
+	public void setPr_uuid(String pr_uuid) {
+		this.pr_uuid = pr_uuid;
+	}
+
+	public String getPr_status() {
+		return pr_status;
+	}
+
+	public void setPr_status(String pr_status) {
+		this.pr_status = pr_status;
+	}
+
+	public Short getPr_issale() {
+		return pr_issale;
+	}
+
+	public void setPr_issale(Short pr_issale) {
+		this.pr_issale = pr_issale;
+	}
+
+	public Short getPr_ispurchase() {
+		return pr_ispurchase;
+	}
+
+	public void setPr_ispurchase(Short pr_ispurchase) {
+		this.pr_ispurchase = pr_ispurchase;
+	}
+
+	public Short getPr_isshow() {
+		return pr_isshow;
+	}
+
+	public void setPr_isshow(Short pr_isshow) {
+		this.pr_isshow = pr_isshow;
+	}
+
+	public Short getPr_ispubsale() {
+		return pr_ispubsale;
+	}
+
+	public void setPr_ispubsale(Short pr_ispubsale) {
+		this.pr_ispubsale = pr_ispubsale;
+	}
+
+	public Long getB2b_id() {
+		return b2b_id;
+	}
+
+	public void setB2b_id(Long b2b_id) {
+		this.b2b_id = b2b_id;
+	}
+
+	public Product map() {
+		Product.Builder builder = Product.newBuilder();
+		if (!NumberUtils.isEmpty(pr_id)) {
+			builder.setPrId(pr_id);
+		}
+		if (!StringUtils.isEmpty(pr_code)) {
+			builder.setPrCode(pr_code);
+		}
+		if (!StringUtils.isEmpty(pr_detail)) {
+			builder.setPrDetail(pr_detail);
+		}
+		if (!StringUtils.isEmpty(pr_spec)) {
+			builder.setPrSpec(pr_spec);
+		}
+		if (!StringUtils.isEmpty(pr_unit)) {
+			builder.setPrUnit(pr_unit);
+		}
+		if (null != pr_zxbzs) {
+			builder.setPrZxbzs(pr_zxbzs);
+		}
+		if (null != pr_zxdhl) {
+			builder.setPrZxdhl(pr_zxdhl);
+		}
+		if (null != pr_leadtime) {
+			builder.setPrLeadtime(pr_leadtime);
+		}
+		if (null != pr_ltinstock) {
+			builder.setPrLtinstock(pr_ltinstock);
+		}
+		if (!StringUtils.isEmpty(pr_brand)) {
+			builder.setPrBrand(pr_brand);
+		}
+		if (!StringUtils.isEmpty(pr_orispeccode)) {
+			builder.setPrOrispeccode(pr_orispeccode);
+		}
+		if (!StringUtils.isEmpty(pr_uuid)) {
+			builder.setPrUuid(pr_uuid);
+		}
+		if (!StringUtils.isEmpty(pr_status)) {
+			builder.setPrStatus(pr_status);
+		}
+		if (!NumberUtils.isEmpty(pr_issale)) {
+			builder.setPrIssale(pr_issale);
+		}
+		if (!NumberUtils.isEmpty(pr_ispurchase)) {
+			builder.setPrIspubsale(pr_ispurchase);
+		}
+		if (!NumberUtils.isEmpty(pr_isshow)) {
+			builder.setPrIsshow(pr_isshow);
+		}
+		if (!NumberUtils.isEmpty(pr_ispubsale)) {
+			builder.setPrIspubsale(pr_ispubsale);
+		}
+		if (!NumberUtils.isEmpty(b2b_id)) {
+			builder.setB2BId(b2b_id);
+		}
+		builder.setPrEnuu(MasterHolder.get().getMa_uu());
+		return builder.build();
+	}
+
+	@Override
+	public Object id() {
+		return pr_id;
+	}
+}

+ 31 - 0
uas-pl-product/src/main/java/com/usoftchina/uas/pl/product/service/ProductService.java

@@ -0,0 +1,31 @@
+package com.usoftchina.uas.pl.product.service;
+
+import com.usoftchina.uas.pl.product.po.ProductPO;
+import com.usoftchina.uas.pl.service.AbstractService;
+import org.springframework.dao.EmptyResultDataAccessException;
+import org.springframework.jdbc.core.BeanPropertyRowMapper;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * @author yingp
+ * @date 2020/1/14
+ */
+@Service
+public class ProductService extends AbstractService {
+
+    /**
+     * 待上传平台物料
+     *
+     * @return
+     */
+    public List<ProductPO> toUploadList() {
+        try {
+            return jdbcTemplate.query("select * from (select pr_id,pr_code,pr_detail,pr_spec,pr_unit,pr_zxbzs,pr_zxdhl,pr_leadtime,pr_ltinstock,pr_brand,pr_issale,pr_ispurchase,pr_isshow,pr_ispubsale,pr_uuid,pr_orispeccode from product where  pr_sendstatus<>'已上传' and  pr_status = '已审核' order by pr_id) where rownum <= 500",
+                    new BeanPropertyRowMapper<>(ProductPO.class));
+        } catch (EmptyResultDataAccessException e) {
+            return null;
+        }
+    }
+}

+ 24 - 0
uas-pl-product/src/main/java/com/usoftchina/uas/pl/product/task/AbstractProductTask.java

@@ -0,0 +1,24 @@
+package com.usoftchina.uas.pl.product.task;
+
+import com.usoft.b2b.external.api.entity.RespHeader;
+import com.usoftchina.uas.pl.product.config.Sdk;
+import com.usoftchina.uas.pl.product.exception.ResponseError;
+import com.usoftchina.uas.pl.task.AbstractTask;
+import com.usoftchina.uas.pl.utils.Const;
+import org.springframework.beans.factory.annotation.Autowired;
+
+/**
+ * @author yingp
+ * @date 2020/1/17
+ */
+public abstract class AbstractProductTask extends AbstractTask {
+
+    @Autowired
+    protected Sdk sdk;
+
+    protected static void assertOk(RespHeader header) {
+        if (Const.OK != header.getCode()) {
+            throw new ResponseError(header);
+        }
+    }
+}

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