作者 陈志颖

合并分支 'dev' 到 'master'

Dev



查看合并请求 !7
正在显示 45 个修改的文件 包含 2036 行增加1718 行删除
1 -# 合伙人项目  
2 -vendor 文件夹如果不是迫不得已,请不要手动修改其中的文件!  
3 -如果手动修改vendor中的文件,需自行进行版本管理。(慎重考虑!慎重考虑!慎重考虑!)  
  1 +# 服务端工作交接事项
  2 +## 合伙人管理后台项目
  3 +
  4 +### 代码以及文档
  5 +- [代码地址](http://gitlab.fjmaimaimai.com/mmm-go/partnermg.git)
  6 +- [项目原型svn](svn://218.106.157.184/repo/项目文件/项目【合伙人】)
  7 +- [yapi-合伙人前端](http://47.97.5.102:36666/project/209/interface/api)
  8 +
  9 +服务端地址
  10 +```
  11 +测试开发环境pg数据库地址:114.55.200.59:31543,开发库:partner_dev,测试库:partner_test
  12 +正式环境pg数据库地址:114.55.200.59:31544,正式库:partner
  13 +
  14 +服务端开发环境地址:http://mmm-partnermg-dev.fjmaimaimai.com
  15 +服务端测试环境地址:http://mmm-partnermg-test.fjmaimaimai.com
  16 +服务端正式环境地址:https://public-interface.fjmaimaimai.com/mmm-partnermg
  17 +```
  18 +### 项目整体
  19 +- 项目使用框架
  20 + - http框架:beego
  21 + - orm框架:go-pg
  22 + - 数据存储:postgresql
  23 + - 项目结构分层:DDD领域驱动
  24 +
  25 +- 项目结构
  26 +```
  27 +├─conf 项目配置文件
  28 +├─deploy 项目部署文件
  29 +├─pkg
  30 +│ ├─application
  31 +│ │ ├─adminPermission 用户权限菜单
  32 +│ │ ├─businessBonus (在0.5.0后已经移除)
  33 +│ │ ├─company 企业公司功能
  34 +│ │ ├─event 事件订阅以及处理
  35 +│ │ ├─factory 工厂类,实例具体的实现(数据仓储)
  36 +│ │ ├─orderinfo 合伙人订单以及分红数据
  37 +│ │ ├─partnerCategory 合伙人分类信息
  38 +│ │ ├─partnerInfo 合伙人信息
  39 +│ │ ├─syncOrder 同步其他系统的订单数据
  40 +│ │ ├─unifiedUserCenter 从企业平台接收企业和管理员用户数据
  41 +│ │ └─users 管理员用户信息
  42 +│ ├─constant 变量配置(数据库等)
  43 +│ ├─domain 领域模型(核心数据处理,接口定义)
  44 +│ │ ├─event 领域事件定义
  45 +│ │ └─service 领域服务定义
  46 +│ ├─infrastructure 基础设施
  47 +│ │ ├─dao 特殊的数据库操作
  48 +│ │ ├─domainService 实现领域服务
  49 +│ │ ├─pg postgresql 数据库模型定义
  50 +│ │ ├─repository 数据仓储具体实现(对应domain定义数据库的数据存储接口)
  51 +│ │ ├─serviceGateway 其他系统服务调用
  52 +│ │
  53 +│ ├─lib
  54 +│ ├─log
  55 +│ └─port 数据接入层(http接入,消息)
  56 +│ ├─beego beego接入
  57 +│ └─consumer kafka消息订阅
  58 +└─vendor
  59 +```
  60 +### 系统对接的外部数据
  61 +
  62 +1. 外部数据来源,接收企业平台发送过来的数据。目前接收的是公司和员工的数据
  63 + 主要内容在文件夹
  64 + partnermg/pkg/application/unifiedUserCenter,
  65 + partnermg/pkg/port/beego/controller/sync_data_controller.go,
  66 + partnermg/pkg/port/beego/routers/routers.go,
  67 + 具体对接需要的数据格式文档地址:
  68 + [yapi-企业平台-子系统对接](http://47.97.5.102:36666/project/187/interface/api)
  69 +
  70 +2. 外部数据来源,接收香米小程序的订单,需要对接kafka消息。
  71 + 主要内容在
  72 + partnermg/pkg/application/syncOrder,
  73 + partnermg/pkg/port/consumer,
  74 + 具体对接需要的数据格式文档地址:
  75 + [yapi-合伙人-后端](http://47.97.5.102:36666/project/211/interface/api/9013)
  76 +
  77 +3. 需要调用外部的api接口,调用企业平台,统一用户中心的接口
  78 + 主要内容在
  79 + partnermg/pkg/infrastructure/serviceGateway
  80 +
  81 +### 系统入口
  82 +- [测试环境--企业平台网站地址](https://enterprise-platform-dev.fjmaimaimai.com)
  83 +- [开发环境--企业平台网站地址](https://enterprise-platform-local.fjmaimaimai.com)
  84 +- 天联共创后台自身没有独立的登录入口,需要经过企业平台进行跳转登录
  85 +
  86 +
  87 +## 建议
  88 +1. vendor 目前作用是存放依赖,加快在容器中的构建速度。
  89 +2. 有"go.mod"文件存在,可以直接删除vendor文件夹。不过相应的dockerfile 也要进行一定的修改。
  90 +3. vendor 文件夹如果不是迫不得已,请不要手动修改其中的文件!可以使用命令 “go mod vendor”。
  91 +如果手动修改vendor中的文件,需自行进行版本管理。(慎重考虑!慎重考虑!慎重考虑!)。
  92 +
  93 +
@@ -4,7 +4,6 @@ go 1.14 @@ -4,7 +4,6 @@ go 1.14
4 4
5 require ( 5 require (
6 github.com/360EntSecGroup-Skylar/excelize/v2 v2.3.1 6 github.com/360EntSecGroup-Skylar/excelize/v2 v2.3.1
7 - github.com/GeeTeam/gt3-golang-sdk v0.0.0-20200116043922-446ca8a507d2  
8 github.com/Shopify/sarama v1.23.1 7 github.com/Shopify/sarama v1.23.1
9 github.com/ajg/form v1.5.1 // indirect 8 github.com/ajg/form v1.5.1 // indirect
10 github.com/astaxie/beego v1.12.2 9 github.com/astaxie/beego v1.12.2
@@ -17,7 +17,7 @@ type CreatePartnerInfoCommand struct { @@ -17,7 +17,7 @@ type CreatePartnerInfoCommand struct {
17 // 状态(1:启用或者0:禁用) 17 // 状态(1:启用或者0:禁用)
18 Status int `json:"status"` 18 Status int `json:"status"`
19 // 合伙类别 19 // 合伙类别
20 - PartnerCategory []int64 `json:"partnerCategory,omitempty"` 20 + PartnerCategory []*domain.PartnerCategory `json:"partnerCategory,omitempty"`
21 //合作时间 21 //合作时间
22 CooperateTime time.Time `json:"cooperateTime"` 22 CooperateTime time.Time `json:"cooperateTime"`
23 // 区域 23 // 区域
@@ -26,6 +26,8 @@ type CreatePartnerInfoCommand struct { @@ -26,6 +26,8 @@ type CreatePartnerInfoCommand struct {
26 Salesman []domain.Salesman `json:"salesman,omitempty"` 26 Salesman []domain.Salesman `json:"salesman,omitempty"`
27 //公司id 27 //公司id
28 CompanyId int64 `json:"companyId"` 28 CompanyId int64 `json:"companyId"`
  29 + //备注
  30 + Remark string `json:"remark"`
29 } 31 }
30 32
31 func (command CreatePartnerInfoCommand) ValidateCommand() error { 33 func (command CreatePartnerInfoCommand) ValidateCommand() error {
  1 +/**
  2 + @author: stevechan
  3 + @date: 2020/12/29
  4 + @note:
  5 +**/
  6 +
  7 +package command
  8 +
  9 +import (
  10 + "gitlab.fjmaimaimai.com/mmm-go/partnermg/pkg/lib"
  11 +)
  12 +
  13 +// 移除合伙人
  14 +type RemovePartnerInfoCommand struct {
  15 + // 合伙人Id
  16 + Id int64 `json:"id" valid:"Required"`
  17 +}
  18 +
  19 +func (command *RemovePartnerInfoCommand) ValidateCommand() error {
  20 + if command.Id == 0 {
  21 + return lib.ThrowError(lib.ARG_ERROR, "合伙人id错误")
  22 + }
  23 + return nil
  24 +}
@@ -10,10 +10,12 @@ import ( @@ -10,10 +10,12 @@ import (
10 type UpdatePartnerInfoCommand struct { 10 type UpdatePartnerInfoCommand struct {
11 // 合伙人Id 11 // 合伙人Id
12 Id int64 `json:"id"` 12 Id int64 `json:"id"`
  13 + // 合伙人姓名
  14 + PartnerName string `json:"partnerName"`
13 // 状态(1:启用或者0:禁用) 15 // 状态(1:启用或者0:禁用)
14 Status int `json:"status"` 16 Status int `json:"status"`
15 // 合伙类别 (1.研发合伙人 2.业务合伙人 3.事业) 17 // 合伙类别 (1.研发合伙人 2.业务合伙人 3.事业)
16 - PartnerCategory []int64 `json:"partnerCategory,omitempty"` 18 + PartnerCategory []*domain.PartnerCategory `json:"partnerCategory,omitempty"`
17 // 区域 19 // 区域
18 RegionInfo *domain.RegionInfo `json:"regionInfo"` 20 RegionInfo *domain.RegionInfo `json:"regionInfo"`
19 //关联业务员 21 //关联业务员
@@ -22,6 +24,8 @@ type UpdatePartnerInfoCommand struct { @@ -22,6 +24,8 @@ type UpdatePartnerInfoCommand struct {
22 CooperateTime time.Time `json:"cooperateTime"` 24 CooperateTime time.Time `json:"cooperateTime"`
23 //公司id 25 //公司id
24 CompanyId int64 `json:"companyId"` 26 CompanyId int64 `json:"companyId"`
  27 + //备注
  28 + Remark string `json:"remark"`
25 } 29 }
26 30
27 func (command *UpdatePartnerInfoCommand) ValidateCommand() error { 31 func (command *UpdatePartnerInfoCommand) ValidateCommand() error {
@@ -31,7 +35,6 @@ func (command *UpdatePartnerInfoCommand) ValidateCommand() error { @@ -31,7 +35,6 @@ func (command *UpdatePartnerInfoCommand) ValidateCommand() error {
31 if command.RegionInfo == nil { 35 if command.RegionInfo == nil {
32 return lib.ThrowError(lib.ARG_ERROR, "区域必填") 36 return lib.ThrowError(lib.ARG_ERROR, "区域必填")
33 } 37 }
34 -  
35 if command.Id == 0 { 38 if command.Id == 0 {
36 return lib.ThrowError(lib.ARG_ERROR, "合伙人id错误") 39 return lib.ThrowError(lib.ARG_ERROR, "合伙人id错误")
37 } 40 }
@@ -2,12 +2,13 @@ package query @@ -2,12 +2,13 @@ package query
2 2
3 type ListPartnerInfoQuery struct { 3 type ListPartnerInfoQuery struct {
4 // 合伙人类别 4 // 合伙人类别
5 - Partnertype int `json:"partnerType"` 5 + PartnerType int `json:"partnerType"`
6 //所属区域 6 //所属区域
7 RegionInfo string `json:"regionInfo"` 7 RegionInfo string `json:"regionInfo"`
8 // 合伙人姓名 8 // 合伙人姓名
9 PartnerName string `json:"partnerName"` 9 PartnerName string `json:"partnerName"`
10 - CompanyId int64 `json:"companyId"` 10 + // 公司id
  11 + CompanyId int64 `json:"companyId"`
11 // 查询偏离量 12 // 查询偏离量
12 Offset int `json:"offset"` 13 Offset int `json:"offset"`
13 // 查询限制 14 // 查询限制
@@ -15,6 +16,5 @@ type ListPartnerInfoQuery struct { @@ -15,6 +16,5 @@ type ListPartnerInfoQuery struct {
15 } 16 }
16 17
17 func (q *ListPartnerInfoQuery) ValidateQuery() error { 18 func (q *ListPartnerInfoQuery) ValidateQuery() error {
18 -  
19 return nil 19 return nil
20 } 20 }
@@ -21,7 +21,13 @@ func NewPartnerInfoService(options map[string]interface{}) *PartnerInfoService { @@ -21,7 +21,13 @@ func NewPartnerInfoService(options map[string]interface{}) *PartnerInfoService {
21 return newPartnerInfoService 21 return newPartnerInfoService
22 } 22 }
23 23
24 -// CreatePartnerInfo 创建合伙人 24 +/**
  25 + * @Author SteveChan
  26 + * @Description // 创建合伙人
  27 + * @Date 15:42 2020/12/29
  28 + * @Param
  29 + * @return
  30 + **/
25 func (PartnerInfoService *PartnerInfoService) CreatePartnerInfo(cmd *command.CreatePartnerInfoCommand) (data *domain.PartnerInfo, err error) { 31 func (PartnerInfoService *PartnerInfoService) CreatePartnerInfo(cmd *command.CreatePartnerInfoCommand) (data *domain.PartnerInfo, err error) {
26 var ( 32 var (
27 transactionContext, _ = factory.CreateTransactionContext(nil) 33 transactionContext, _ = factory.CreateTransactionContext(nil)
@@ -35,16 +41,21 @@ func (PartnerInfoService *PartnerInfoService) CreatePartnerInfo(cmd *command.Cre @@ -35,16 +41,21 @@ func (PartnerInfoService *PartnerInfoService) CreatePartnerInfo(cmd *command.Cre
35 defer func() { 41 defer func() {
36 transactionContext.RollbackTransaction() 42 transactionContext.RollbackTransaction()
37 }() 43 }()
  44 +
38 //检查账号是否存在 45 //检查账号是否存在
39 var ( 46 var (
40 - partnerinfoDao *dao.PartnerInfoDao 47 + partnerInfoDao *dao.PartnerInfoDao
  48 + partnerInfoRepository domain.PartnerInfoRepository
  49 + categoryRepository domain.PartnerCategoryRepository
  50 + categories []domain.PartnerCategory
41 ) 51 )
42 - if partnerinfoDao, err = factory.CreatePartnerInfoDao(map[string]interface{}{ 52 + if partnerInfoDao, err = factory.CreatePartnerInfoDao(map[string]interface{}{
43 "transactionContext": transactionContext, 53 "transactionContext": transactionContext,
44 }); err != nil { 54 }); err != nil {
45 return nil, lib.ThrowError(lib.TRANSACTION_ERROR, err.Error()) 55 return nil, lib.ThrowError(lib.TRANSACTION_ERROR, err.Error())
46 } 56 }
47 - ok, err := partnerinfoDao.PartnerAccountExist(cmd.Account, cmd.CompanyId) 57 +
  58 + ok, err := partnerInfoDao.PartnerAccountExist(cmd.Account, cmd.CompanyId)
48 if err != nil { 59 if err != nil {
49 return nil, lib.ThrowError(lib.TRANSACTION_ERROR, err.Error()) 60 return nil, lib.ThrowError(lib.TRANSACTION_ERROR, err.Error())
50 } 61 }
@@ -52,11 +63,6 @@ func (PartnerInfoService *PartnerInfoService) CreatePartnerInfo(cmd *command.Cre @@ -52,11 +63,6 @@ func (PartnerInfoService *PartnerInfoService) CreatePartnerInfo(cmd *command.Cre
52 return nil, lib.ThrowError(lib.BUSINESS_ERROR, "账号已存在") 63 return nil, lib.ThrowError(lib.BUSINESS_ERROR, "账号已存在")
53 } 64 }
54 65
55 - var (  
56 - partnerInfoRepository domain.PartnerInfoRepository  
57 - categoryRepository domain.PartnerCategoryRepository  
58 - categorys []domain.PartnerCategory  
59 - )  
60 if partnerInfoRepository, err = factory.CreatePartnerInfoRepository(map[string]interface{}{ 66 if partnerInfoRepository, err = factory.CreatePartnerInfoRepository(map[string]interface{}{
61 "transactionContext": transactionContext, 67 "transactionContext": transactionContext,
62 }); err != nil { 68 }); err != nil {
@@ -67,13 +73,60 @@ func (PartnerInfoService *PartnerInfoService) CreatePartnerInfo(cmd *command.Cre @@ -67,13 +73,60 @@ func (PartnerInfoService *PartnerInfoService) CreatePartnerInfo(cmd *command.Cre
67 }); err != nil { 73 }); err != nil {
68 return nil, lib.ThrowError(lib.INTERNAL_SERVER_ERROR, err.Error()) 74 return nil, lib.ThrowError(lib.INTERNAL_SERVER_ERROR, err.Error())
69 } 75 }
70 - _, categorys, err = categoryRepository.Find(domain.PartnerCategoryFindQuery{  
71 - Ids: cmd.PartnerCategory, 76 +
  77 + // 获取所有合伙人类型
  78 + var categoryMap = make(map[int64]string)
  79 + _, categories, err = categoryRepository.Find(domain.PartnerCategoryFindQuery{
  80 + Ids: []int64{},
72 }) 81 })
73 if err != nil { 82 if err != nil {
74 e := fmt.Sprintf("获取合伙人分类数据失败:%s", err) 83 e := fmt.Sprintf("获取合伙人分类数据失败:%s", err)
75 return nil, lib.ThrowError(lib.INTERNAL_SERVER_ERROR, e) 84 return nil, lib.ThrowError(lib.INTERNAL_SERVER_ERROR, e)
76 } 85 }
  86 + if len(categories) > 0 {
  87 + for _, category := range categories {
  88 + categoryMap[category.Id] = category.Name
  89 + }
  90 + }
  91 +
  92 + // id去重
  93 + num := make(map[int64]bool)
  94 + for _, partnerCategory := range cmd.PartnerCategory {
  95 + if !num[partnerCategory.Id] {
  96 + num[partnerCategory.Id] = true
  97 + } else {
  98 + return nil, lib.ThrowError(lib.BUSINESS_ERROR, "合伙类型不能重复")
  99 + }
  100 + }
  101 +
  102 + // 编号去重
  103 + for _, partnerCategory := range cmd.PartnerCategory {
  104 + if ok, err := partnerInfoDao.PartnerCodeExist(partnerCategory.Id, partnerCategory.Code, cmd.CompanyId, 0); err != nil {
  105 + return nil, lib.ThrowError(lib.TRANSACTION_ERROR, err.Error())
  106 + } else if ok {
  107 + return nil, lib.ThrowError(lib.BUSINESS_ERROR, categoryMap[partnerCategory.Id]+"编号"+partnerCategory.Code+"已存在")
  108 + }
  109 + }
  110 +
  111 + var ids []int64
  112 + for _, partnerCategory := range cmd.PartnerCategory {
  113 + ids = append(ids, partnerCategory.Id)
  114 + }
  115 + _, categories, err = categoryRepository.Find(domain.PartnerCategoryFindQuery{
  116 + Ids: ids,
  117 + })
  118 + if err != nil {
  119 + e := fmt.Sprintf("获取合伙人分类数据失败:%s", err)
  120 + return nil, lib.ThrowError(lib.INTERNAL_SERVER_ERROR, e)
  121 + }
  122 + for i, category := range categories {
  123 + for _, partnerCategory := range cmd.PartnerCategory {
  124 + if category.Id == partnerCategory.Id {
  125 + categories[i].Code = partnerCategory.Code
  126 + }
  127 + }
  128 + }
  129 +
77 newPartnerInfo := domain.PartnerInfo{ 130 newPartnerInfo := domain.PartnerInfo{
78 Partner: domain.Partner{ 131 Partner: domain.Partner{
79 Account: cmd.Account, 132 Account: cmd.Account,
@@ -86,7 +139,8 @@ func (PartnerInfoService *PartnerInfoService) CreatePartnerInfo(cmd *command.Cre @@ -86,7 +139,8 @@ func (PartnerInfoService *PartnerInfoService) CreatePartnerInfo(cmd *command.Cre
86 Salesman: cmd.Salesman, 139 Salesman: cmd.Salesman,
87 CooperateTime: cmd.CooperateTime, 140 CooperateTime: cmd.CooperateTime,
88 CompanyId: cmd.CompanyId, 141 CompanyId: cmd.CompanyId,
89 - PartnerCategoryInfos: categorys, 142 + PartnerCategoryInfos: categories,
  143 + Remark: cmd.Remark,
90 } 144 }
91 if err = partnerInfoRepository.Save(&newPartnerInfo); err != nil { 145 if err = partnerInfoRepository.Save(&newPartnerInfo); err != nil {
92 return nil, lib.ThrowError(lib.INTERNAL_SERVER_ERROR, err.Error()) 146 return nil, lib.ThrowError(lib.INTERNAL_SERVER_ERROR, err.Error())
@@ -106,11 +160,18 @@ func (PartnerInfoService *PartnerInfoService) CreatePartnerInfo(cmd *command.Cre @@ -106,11 +160,18 @@ func (PartnerInfoService *PartnerInfoService) CreatePartnerInfo(cmd *command.Cre
106 return &newPartnerInfo, nil 160 return &newPartnerInfo, nil
107 } 161 }
108 162
109 -// GetPartnerInfo 返回合伙人 163 +/**
  164 + * @Author SteveChan
  165 + * @Description // 返回合伙人,增加合伙人编号字段
  166 + * @Date 15:43 2020/12/29
  167 + * @Param
  168 + * @return
  169 + **/
110 func (PartnerInfoService *PartnerInfoService) GetPartnerInfo(q query.GetPartnerInfoQuery) (data *domain.PartnerInfo, err error) { 170 func (PartnerInfoService *PartnerInfoService) GetPartnerInfo(q query.GetPartnerInfoQuery) (data *domain.PartnerInfo, err error) {
111 var ( 171 var (
112 transactionContext, _ = factory.CreateTransactionContext(nil) 172 transactionContext, _ = factory.CreateTransactionContext(nil)
113 ) 173 )
  174 +
114 if err = q.ValidateQuery(); err != nil { 175 if err = q.ValidateQuery(); err != nil {
115 return nil, lib.ThrowError(lib.ARG_ERROR, err.Error()) 176 return nil, lib.ThrowError(lib.ARG_ERROR, err.Error())
116 } 177 }
@@ -120,17 +181,21 @@ func (PartnerInfoService *PartnerInfoService) GetPartnerInfo(q query.GetPartnerI @@ -120,17 +181,21 @@ func (PartnerInfoService *PartnerInfoService) GetPartnerInfo(q query.GetPartnerI
120 defer func() { 181 defer func() {
121 transactionContext.RollbackTransaction() 182 transactionContext.RollbackTransaction()
122 }() 183 }()
  184 +
123 var ( 185 var (
124 PartnerInfoRepository domain.PartnerInfoRepository 186 PartnerInfoRepository domain.PartnerInfoRepository
125 categoryRepository domain.PartnerCategoryRepository 187 categoryRepository domain.PartnerCategoryRepository
126 - categorys []domain.PartnerCategory 188 + categories []domain.PartnerCategory
127 partnerData *domain.PartnerInfo 189 partnerData *domain.PartnerInfo
128 ) 190 )
  191 +
129 if PartnerInfoRepository, err = factory.CreatePartnerInfoRepository(map[string]interface{}{ 192 if PartnerInfoRepository, err = factory.CreatePartnerInfoRepository(map[string]interface{}{
130 "transactionContext": transactionContext, 193 "transactionContext": transactionContext,
131 }); err != nil { 194 }); err != nil {
132 return nil, lib.ThrowError(lib.INTERNAL_SERVER_ERROR, err.Error()) 195 return nil, lib.ThrowError(lib.INTERNAL_SERVER_ERROR, err.Error())
133 } 196 }
  197 +
  198 + // 获取合伙人数据
134 partnerData, err = PartnerInfoRepository.FindOne(domain.PartnerFindOneQuery{ 199 partnerData, err = PartnerInfoRepository.FindOne(domain.PartnerFindOneQuery{
135 UserId: q.Id, CompanyId: q.CompanyId, 200 UserId: q.Id, CompanyId: q.CompanyId,
136 }) 201 })
@@ -140,33 +205,49 @@ func (PartnerInfoService *PartnerInfoService) GetPartnerInfo(q query.GetPartnerI @@ -140,33 +205,49 @@ func (PartnerInfoService *PartnerInfoService) GetPartnerInfo(q query.GetPartnerI
140 if !partnerData.IsCompany(q.CompanyId) { 205 if !partnerData.IsCompany(q.CompanyId) {
141 return nil, lib.ThrowError(lib.BUSINESS_ERROR, "企业信息异常操作") 206 return nil, lib.ThrowError(lib.BUSINESS_ERROR, "企业信息异常操作")
142 } 207 }
  208 +
  209 + // 获取合伙人类别
143 if categoryRepository, err = factory.CreatePartnerCategoryRepository(map[string]interface{}{ 210 if categoryRepository, err = factory.CreatePartnerCategoryRepository(map[string]interface{}{
144 "transactionContext": transactionContext, 211 "transactionContext": transactionContext,
145 }); err != nil { 212 }); err != nil {
146 return nil, lib.ThrowError(lib.INTERNAL_SERVER_ERROR, err.Error()) 213 return nil, lib.ThrowError(lib.INTERNAL_SERVER_ERROR, err.Error())
147 } 214 }
148 - categoryIds := []int64{} 215 + var categoryIds []int64
149 for _, v := range partnerData.PartnerCategoryInfos { 216 for _, v := range partnerData.PartnerCategoryInfos {
150 categoryIds = append(categoryIds, v.Id) 217 categoryIds = append(categoryIds, v.Id)
151 } 218 }
152 if len(categoryIds) > 0 { 219 if len(categoryIds) > 0 {
153 - _, categorys, err = categoryRepository.Find(domain.PartnerCategoryFindQuery{ 220 + _, categories, err = categoryRepository.Find(domain.PartnerCategoryFindQuery{
154 Ids: categoryIds, 221 Ids: categoryIds,
155 }) 222 })
156 if err != nil { 223 if err != nil {
157 return nil, lib.ThrowError(lib.INTERNAL_SERVER_ERROR, err.Error()) 224 return nil, lib.ThrowError(lib.INTERNAL_SERVER_ERROR, err.Error())
158 } 225 }
  226 + for i, category := range categories {
  227 + for _, partnerCategory := range partnerData.PartnerCategoryInfos {
  228 + if category.Id == partnerCategory.Id {
  229 + categories[i].Code = partnerCategory.Code
  230 + }
  231 + }
  232 + }
159 } 233 }
160 - partnerData.PartnerCategoryInfos = categorys 234 + partnerData.PartnerCategoryInfos = categories
161 err = transactionContext.CommitTransaction() 235 err = transactionContext.CommitTransaction()
162 return partnerData, nil 236 return partnerData, nil
163 } 237 }
164 238
165 -//UpdatePartnerInfo 更新合伙人 239 +/**
  240 + * @Author SteveChan
  241 + * @Description // 更新合伙人
  242 + * @Date 00:07 2020/12/30
  243 + * @Param
  244 + * @return
  245 + **/
166 func (PartnerInfoService *PartnerInfoService) UpdatePartnerInfo(cmd *command.UpdatePartnerInfoCommand) (err error) { 246 func (PartnerInfoService *PartnerInfoService) UpdatePartnerInfo(cmd *command.UpdatePartnerInfoCommand) (err error) {
167 var ( 247 var (
168 transactionContext, _ = factory.CreateTransactionContext(nil) 248 transactionContext, _ = factory.CreateTransactionContext(nil)
169 ) 249 )
  250 +
170 if err = cmd.ValidateCommand(); err != nil { 251 if err = cmd.ValidateCommand(); err != nil {
171 return application.ThrowError(application.ARG_ERROR, err.Error()) 252 return application.ThrowError(application.ARG_ERROR, err.Error())
172 } 253 }
@@ -176,30 +257,90 @@ func (PartnerInfoService *PartnerInfoService) UpdatePartnerInfo(cmd *command.Upd @@ -176,30 +257,90 @@ func (PartnerInfoService *PartnerInfoService) UpdatePartnerInfo(cmd *command.Upd
176 defer func() { 257 defer func() {
177 transactionContext.RollbackTransaction() 258 transactionContext.RollbackTransaction()
178 }() 259 }()
  260 +
179 var ( 261 var (
180 partnerInfoRepository domain.PartnerInfoRepository 262 partnerInfoRepository domain.PartnerInfoRepository
181 categoryRepository domain.PartnerCategoryRepository 263 categoryRepository domain.PartnerCategoryRepository
182 - categorys []domain.PartnerCategory 264 + categories []domain.PartnerCategory
  265 + partnerInfoDao *dao.PartnerInfoDao
183 ) 266 )
  267 +
  268 + if partnerInfoDao, err = factory.CreatePartnerInfoDao(map[string]interface{}{
  269 + "transactionContext": transactionContext,
  270 + }); err != nil {
  271 + return lib.ThrowError(lib.TRANSACTION_ERROR, err.Error())
  272 + }
  273 +
184 if partnerInfoRepository, err = factory.CreatePartnerInfoRepository(map[string]interface{}{ 274 if partnerInfoRepository, err = factory.CreatePartnerInfoRepository(map[string]interface{}{
185 "transactionContext": transactionContext, 275 "transactionContext": transactionContext,
186 }); err != nil { 276 }); err != nil {
187 return lib.ThrowError(lib.TRANSACTION_ERROR, err.Error()) 277 return lib.ThrowError(lib.TRANSACTION_ERROR, err.Error())
188 } 278 }
  279 +
189 if categoryRepository, err = factory.CreatePartnerCategoryRepository(map[string]interface{}{ 280 if categoryRepository, err = factory.CreatePartnerCategoryRepository(map[string]interface{}{
190 "transactionContext": transactionContext, 281 "transactionContext": transactionContext,
191 }); err != nil { 282 }); err != nil {
192 return lib.ThrowError(lib.INTERNAL_SERVER_ERROR, err.Error()) 283 return lib.ThrowError(lib.INTERNAL_SERVER_ERROR, err.Error())
193 } 284 }
194 - _, categorys, err = categoryRepository.Find(domain.PartnerCategoryFindQuery{  
195 - Ids: cmd.PartnerCategory, 285 +
  286 + // 获取合伙人类型
  287 + var categoryMap = make(map[int64]string)
  288 + _, categories, err = categoryRepository.Find(domain.PartnerCategoryFindQuery{
  289 + Ids: []int64{},
196 }) 290 })
197 if err != nil { 291 if err != nil {
198 e := fmt.Sprintf("获取合伙人分类数据失败:%s", err) 292 e := fmt.Sprintf("获取合伙人分类数据失败:%s", err)
199 return lib.ThrowError(lib.INTERNAL_SERVER_ERROR, e) 293 return lib.ThrowError(lib.INTERNAL_SERVER_ERROR, e)
200 } 294 }
  295 + if len(categories) > 0 {
  296 + for _, category := range categories {
  297 + categoryMap[category.Id] = category.Name
  298 + }
  299 + }
  300 +
  301 + // id去重
  302 + num := make(map[int64]bool)
  303 + for _, partnerCategory := range cmd.PartnerCategory {
  304 + if !num[partnerCategory.Id] {
  305 + num[partnerCategory.Id] = true
  306 + } else {
  307 + return lib.ThrowError(lib.BUSINESS_ERROR, "合伙类型不能重复")
  308 + }
  309 + }
  310 +
  311 + // 编号去重
  312 + for _, partnerCategory := range cmd.PartnerCategory {
  313 + if ok, err := partnerInfoDao.PartnerCodeExist(partnerCategory.Id, partnerCategory.Code, cmd.CompanyId, cmd.Id); err != nil {
  314 + return lib.ThrowError(lib.TRANSACTION_ERROR, err.Error())
  315 + } else if ok {
  316 + return lib.ThrowError(lib.BUSINESS_ERROR, categoryMap[partnerCategory.Id]+"编号"+partnerCategory.Code+"已存在")
  317 + }
  318 + }
  319 +
  320 + var ids []int64
  321 + for _, partnerCategory := range cmd.PartnerCategory {
  322 + ids = append(ids, partnerCategory.Id)
  323 + }
  324 +
  325 + _, categories, err = categoryRepository.Find(domain.PartnerCategoryFindQuery{
  326 + Ids: ids,
  327 + })
  328 + if err != nil {
  329 + e := fmt.Sprintf("获取合伙人分类数据失败:%s", err)
  330 + return lib.ThrowError(lib.INTERNAL_SERVER_ERROR, e)
  331 + }
  332 +
  333 + for i, category := range categories {
  334 + for _, partnerCategory := range cmd.PartnerCategory {
  335 + if category.Id == partnerCategory.Id {
  336 + categories[i].Code = partnerCategory.Code
  337 + }
  338 + }
  339 + }
  340 +
201 partnerInfo, err := partnerInfoRepository.FindOne(domain.PartnerFindOneQuery{ 341 partnerInfo, err := partnerInfoRepository.FindOne(domain.PartnerFindOneQuery{
202 - UserId: cmd.Id, CompanyId: cmd.CompanyId, 342 + UserId: cmd.Id,
  343 + CompanyId: cmd.CompanyId,
203 }) 344 })
204 if err != nil { 345 if err != nil {
205 return lib.ThrowError(lib.INTERNAL_SERVER_ERROR, err.Error()) 346 return lib.ThrowError(lib.INTERNAL_SERVER_ERROR, err.Error())
@@ -207,11 +348,15 @@ func (PartnerInfoService *PartnerInfoService) UpdatePartnerInfo(cmd *command.Upd @@ -207,11 +348,15 @@ func (PartnerInfoService *PartnerInfoService) UpdatePartnerInfo(cmd *command.Upd
207 if !partnerInfo.IsCompany(cmd.CompanyId) { 348 if !partnerInfo.IsCompany(cmd.CompanyId) {
208 return lib.ThrowError(lib.BUSINESS_ERROR, "异常操作") 349 return lib.ThrowError(lib.BUSINESS_ERROR, "异常操作")
209 } 350 }
  351 +
  352 + partnerInfo.Partner.PartnerName = cmd.PartnerName
210 partnerInfo.Salesman = cmd.Salesman 353 partnerInfo.Salesman = cmd.Salesman
211 partnerInfo.Status = cmd.Status 354 partnerInfo.Status = cmd.Status
212 partnerInfo.RegionInfo = *cmd.RegionInfo 355 partnerInfo.RegionInfo = *cmd.RegionInfo
213 partnerInfo.CooperateTime = cmd.CooperateTime 356 partnerInfo.CooperateTime = cmd.CooperateTime
214 - partnerInfo.PartnerCategoryInfos = categorys 357 + partnerInfo.PartnerCategoryInfos = categories
  358 + partnerInfo.Remark = cmd.Remark
  359 +
215 if err = partnerInfoRepository.Save(partnerInfo); err != nil { 360 if err = partnerInfoRepository.Save(partnerInfo); err != nil {
216 return lib.ThrowError(lib.INTERNAL_SERVER_ERROR, err.Error()) 361 return lib.ThrowError(lib.INTERNAL_SERVER_ERROR, err.Error())
217 } 362 }
@@ -231,7 +376,13 @@ func (PartnerInfoService *PartnerInfoService) UpdatePartnerInfo(cmd *command.Upd @@ -231,7 +376,13 @@ func (PartnerInfoService *PartnerInfoService) UpdatePartnerInfo(cmd *command.Upd
231 return 376 return
232 } 377 }
233 378
234 -// ListPartnerInfo 合伙人列表 379 +/**
  380 + * @Author SteveChan
  381 + * @Description //合伙人列表,返回合伙人编号
  382 + * @Date 00:07 2020/12/30
  383 + * @Param
  384 + * @return
  385 + **/
235 func (PartnerInfoService *PartnerInfoService) ListPartnerInfo(listPartnerInfoQuery *query.ListPartnerInfoQuery) (int, []domain.PartnerInfo, error) { 386 func (PartnerInfoService *PartnerInfoService) ListPartnerInfo(listPartnerInfoQuery *query.ListPartnerInfoQuery) (int, []domain.PartnerInfo, error) {
236 var ( 387 var (
237 transactionContext, _ = factory.CreateTransactionContext(nil) 388 transactionContext, _ = factory.CreateTransactionContext(nil)
@@ -246,14 +397,13 @@ func (PartnerInfoService *PartnerInfoService) ListPartnerInfo(listPartnerInfoQue @@ -246,14 +397,13 @@ func (PartnerInfoService *PartnerInfoService) ListPartnerInfo(listPartnerInfoQue
246 return 0, nil, lib.ThrowError(lib.TRANSACTION_ERROR, err.Error()) 397 return 0, nil, lib.ThrowError(lib.TRANSACTION_ERROR, err.Error())
247 } 398 }
248 defer func() { 399 defer func() {
249 -  
250 transactionContext.RollbackTransaction() 400 transactionContext.RollbackTransaction()
251 -  
252 }() 401 }()
  402 +
253 var ( 403 var (
254 partnerInfoRepository domain.PartnerInfoRepository 404 partnerInfoRepository domain.PartnerInfoRepository
255 categoryRepository domain.PartnerCategoryRepository 405 categoryRepository domain.PartnerCategoryRepository
256 - categorys []domain.PartnerCategory 406 + categories []domain.PartnerCategory
257 ) 407 )
258 if partnerInfoRepository, err = factory.CreatePartnerInfoRepository(map[string]interface{}{ 408 if partnerInfoRepository, err = factory.CreatePartnerInfoRepository(map[string]interface{}{
259 "transactionContext": transactionContext, 409 "transactionContext": transactionContext,
@@ -271,8 +421,8 @@ func (PartnerInfoService *PartnerInfoService) ListPartnerInfo(listPartnerInfoQue @@ -271,8 +421,8 @@ func (PartnerInfoService *PartnerInfoService) ListPartnerInfo(listPartnerInfoQue
271 PartnerName: listPartnerInfoQuery.PartnerName, 421 PartnerName: listPartnerInfoQuery.PartnerName,
272 CompanyId: listPartnerInfoQuery.CompanyId, 422 CompanyId: listPartnerInfoQuery.CompanyId,
273 } 423 }
274 - if listPartnerInfoQuery.Partnertype > 0 {  
275 - queryOption.PartnerCategory = []int{listPartnerInfoQuery.Partnertype} 424 + if listPartnerInfoQuery.PartnerType > 0 {
  425 + queryOption.PartnerCategory = []int{listPartnerInfoQuery.PartnerType}
276 } 426 }
277 // RegionInfo 427 // RegionInfo
278 if len(listPartnerInfoQuery.RegionInfo) > 0 { 428 if len(listPartnerInfoQuery.RegionInfo) > 0 {
@@ -284,18 +434,19 @@ func (PartnerInfoService *PartnerInfoService) ListPartnerInfo(listPartnerInfoQue @@ -284,18 +434,19 @@ func (PartnerInfoService *PartnerInfoService) ListPartnerInfo(listPartnerInfoQue
284 if count, err = partnerInfoRepository.CountAll(queryOption); err != nil { 434 if count, err = partnerInfoRepository.CountAll(queryOption); err != nil {
285 return 0, nil, lib.ThrowError(lib.INTERNAL_SERVER_ERROR, err.Error()) 435 return 0, nil, lib.ThrowError(lib.INTERNAL_SERVER_ERROR, err.Error())
286 } 436 }
287 - _, categorys, err = categoryRepository.Find(domain.PartnerCategoryFindQuery{}) 437 + _, categories, err = categoryRepository.Find(domain.PartnerCategoryFindQuery{})
288 if err != nil { 438 if err != nil {
289 return count, partnerInfos, lib.ThrowError(lib.INTERNAL_SERVER_ERROR, err.Error()) 439 return count, partnerInfos, lib.ThrowError(lib.INTERNAL_SERVER_ERROR, err.Error())
290 } 440 }
291 - categorysMap := make(map[int64]domain.PartnerCategory)  
292 - for i := range categorys {  
293 - categorysMap[categorys[i].Id] = categorys[i] 441 + categoriesMap := make(map[int64]domain.PartnerCategory)
  442 + for i := range categories {
  443 + categoriesMap[categories[i].Id] = categories[i]
294 } 444 }
295 for i := range partnerInfos { 445 for i := range partnerInfos {
296 - categoryInPartner := []domain.PartnerCategory{} 446 + var categoryInPartner []domain.PartnerCategory
297 for _, vv := range partnerInfos[i].PartnerCategoryInfos { 447 for _, vv := range partnerInfos[i].PartnerCategoryInfos {
298 - if categoryData, ok := categorysMap[vv.Id]; ok { 448 + if categoryData, ok := categoriesMap[vv.Id]; ok {
  449 + categoryData.Code = vv.Code
299 categoryInPartner = append(categoryInPartner, categoryData) 450 categoryInPartner = append(categoryInPartner, categoryData)
300 } 451 }
301 } 452 }
@@ -307,6 +458,61 @@ func (PartnerInfoService *PartnerInfoService) ListPartnerInfo(listPartnerInfoQue @@ -307,6 +458,61 @@ func (PartnerInfoService *PartnerInfoService) ListPartnerInfo(listPartnerInfoQue
307 return count, partnerInfos, nil 458 return count, partnerInfos, nil
308 } 459 }
309 460
  461 +/**
  462 + * @Author SteveChan
  463 + * @Description // 移除合伙人
  464 + * @Date 16:40 2020/12/29
  465 + * @Param
  466 + * @return
  467 + **/
  468 +func (PartnerInfoService *PartnerInfoService) RemovePartnerInfo(cmd command.RemovePartnerInfoCommand) (err error) {
  469 + var (
  470 + transactionContext, _ = factory.CreateTransactionContext(nil)
  471 + )
  472 + if err = cmd.ValidateCommand(); err != nil {
  473 + return application.ThrowError(application.ARG_ERROR, err.Error())
  474 + }
  475 + if err = transactionContext.StartTransaction(); err != nil {
  476 + return err
  477 + }
  478 + defer func() {
  479 + transactionContext.RollbackTransaction()
  480 + }()
  481 +
  482 + var (
  483 + partnerInfoRepository domain.PartnerInfoRepository
  484 + orderBaseRepository domain.OrderBaseRepository
  485 + orders []domain.OrderBase
  486 + )
  487 +
  488 + if partnerInfoRepository, err = factory.CreatePartnerInfoRepository(map[string]interface{}{
  489 + "transactionContext": transactionContext,
  490 + }); err != nil {
  491 + return lib.ThrowError(lib.INTERNAL_SERVER_ERROR, err.Error())
  492 + }
  493 +
  494 + if orderBaseRepository, err = factory.CreateOrderBaseRepository(map[string]interface{}{
  495 + "transactionContext": transactionContext,
  496 + }); err != nil {
  497 + return lib.ThrowError(lib.INTERNAL_SERVER_ERROR, err.Error())
  498 + }
  499 +
  500 + // 判断合伙人是否有业务数据
  501 + orders, _, err = orderBaseRepository.Find(domain.OrderBaseFindQuery{
  502 + PartnerId: cmd.Id,
  503 + })
  504 + if len(orders) > 0 {
  505 + return lib.ThrowError(lib.BUSINESS_ERROR, "该合伙人有业务数据,不可删除!")
  506 + }
  507 +
  508 + if err = partnerInfoRepository.Remove(cmd.Id); err != nil {
  509 + return lib.ThrowError(lib.INTERNAL_SERVER_ERROR, err.Error())
  510 + }
  511 +
  512 + transactionContext.CommitTransaction()
  513 + return nil
  514 +}
  515 +
310 func (PartnerInfoService *PartnerInfoService) UpdateStatus(cmd command.StatusPartnerInfoCommand) (err error) { 516 func (PartnerInfoService *PartnerInfoService) UpdateStatus(cmd command.StatusPartnerInfoCommand) (err error) {
311 if len(cmd.Ids) == 0 { 517 if len(cmd.Ids) == 0 {
312 return nil 518 return nil
@@ -324,14 +530,14 @@ func (PartnerInfoService *PartnerInfoService) UpdateStatus(cmd command.StatusPar @@ -324,14 +530,14 @@ func (PartnerInfoService *PartnerInfoService) UpdateStatus(cmd command.StatusPar
324 transactionContext.RollbackTransaction() 530 transactionContext.RollbackTransaction()
325 }() 531 }()
326 var ( 532 var (
327 - partnerinfoDao *dao.PartnerInfoDao 533 + partnerInfoDao *dao.PartnerInfoDao
328 ) 534 )
329 - if partnerinfoDao, err = factory.CreatePartnerInfoDao(map[string]interface{}{ 535 + if partnerInfoDao, err = factory.CreatePartnerInfoDao(map[string]interface{}{
330 "transactionContext": transactionContext, 536 "transactionContext": transactionContext,
331 }); err != nil { 537 }); err != nil {
332 return lib.ThrowError(lib.TRANSACTION_ERROR, err.Error()) 538 return lib.ThrowError(lib.TRANSACTION_ERROR, err.Error())
333 } 539 }
334 - err = partnerinfoDao.UpdatePartnerStatus(cmd.Ids, cmd.CompanyId, cmd.Status) 540 + err = partnerInfoDao.UpdatePartnerStatus(cmd.Ids, cmd.CompanyId, cmd.Status)
335 if err != nil { 541 if err != nil {
336 e := fmt.Sprintf("更新合伙人(id=%v)的数据失败;%s", cmd.Ids, err) 542 e := fmt.Sprintf("更新合伙人(id=%v)的数据失败;%s", cmd.Ids, err)
337 return lib.ThrowError(lib.INTERNAL_SERVER_ERROR, e) 543 return lib.ThrowError(lib.INTERNAL_SERVER_ERROR, e)
@@ -16,7 +16,7 @@ import ( @@ -16,7 +16,7 @@ import (
16 16
17 //从其他系统接收订单数据 17 //从其他系统接收订单数据
18 const ( 18 const (
19 - BEST_SHOP_UNIONID string = "gh_18eb644002fb" //海鲜干货小程序原始id 19 + BEST_SHOP_UNIONID string = "gh_18eb644002fb" //香米小程序原始id
20 ) 20 )
21 21
22 type SyncOrderService struct { 22 type SyncOrderService struct {
@@ -79,6 +79,7 @@ func (s SyncOrderService) SyncOrderFromBestshop(cmd command.CreateOrderFromBests @@ -79,6 +79,7 @@ func (s SyncOrderService) SyncOrderFromBestshop(cmd command.CreateOrderFromBests
79 // 79 //
80 logs.Warning("订单数据已存在:order_code=%s", cmd.OrderCode) 80 logs.Warning("订单数据已存在:order_code=%s", cmd.OrderCode)
81 } else { 81 } else {
  82 + //复制数据到order_base表
82 err = s.CreateOrderFromBestshop(cmd) 83 err = s.CreateOrderFromBestshop(cmd)
83 } 84 }
84 return err 85 return err
@@ -225,6 +226,8 @@ func (s SyncOrderService) copyOrderBestshopToOrderBase(orderBestshop *domain.Ord @@ -225,6 +226,8 @@ func (s SyncOrderService) copyOrderBestshopToOrderBase(orderBestshop *domain.Ord
225 return lib.ThrowError(lib.INTERNAL_SERVER_ERROR, e) 226 return lib.ThrowError(lib.INTERNAL_SERVER_ERROR, e)
226 } 227 }
227 for _, v := range companyData.Applets { 228 for _, v := range companyData.Applets {
  229 + //BEST_SHOP_UNIONID string = "gh_18eb644002fb" //香米小程序原始id
  230 + //接收香米小程序的订单数据
228 if len(v.Id) > 0 { 231 if len(v.Id) > 0 {
229 canCopyOrder = true 232 canCopyOrder = true
230 } 233 }
@@ -237,7 +240,7 @@ func (s SyncOrderService) copyOrderBestshopToOrderBase(orderBestshop *domain.Ord @@ -237,7 +240,7 @@ func (s SyncOrderService) copyOrderBestshopToOrderBase(orderBestshop *domain.Ord
237 orderbase domain.OrderBase 240 orderbase domain.OrderBase
238 ordergoods []domain.OrderGood 241 ordergoods []domain.OrderGood
239 ) 242 )
240 - //TODO 添加orderBase 243 + //添加orderBase
241 orderBestshop.CopyToOrderBase(&orderbase) 244 orderBestshop.CopyToOrderBase(&orderbase)
242 orderbase.CompanyId = companyData.Id 245 orderbase.CompanyId = companyData.Id
243 for i := range orderBestshop.Goods { 246 for i := range orderBestshop.Goods {
@@ -245,13 +248,15 @@ func (s SyncOrderService) copyOrderBestshopToOrderBase(orderBestshop *domain.Ord @@ -245,13 +248,15 @@ func (s SyncOrderService) copyOrderBestshopToOrderBase(orderBestshop *domain.Ord
245 orderBestshop.Goods[i].CopyToOrderGood(&good) 248 orderBestshop.Goods[i].CopyToOrderGood(&good)
246 good.CompanyId = partnerData.CompanyId 249 good.CompanyId = partnerData.CompanyId
247 good.Compute() 250 good.Compute()
  251 + //初始接收的订单按照待支付状态处理
248 good.CurrentBonusStatus.WartPayPartnerBonus(&good) 252 good.CurrentBonusStatus.WartPayPartnerBonus(&good)
249 ordergoods = append(ordergoods, good) 253 ordergoods = append(ordergoods, good)
250 } 254 }
251 orderbase.Goods = ordergoods 255 orderbase.Goods = ordergoods
252 orderbase.PartnerId = partnerData.Partner.Id 256 orderbase.PartnerId = partnerData.Partner.Id
253 orderbase.CompanyId = partnerData.CompanyId 257 orderbase.CompanyId = partnerData.CompanyId
254 - orderbase.PartnerCategory = domain.PartnerCategory{Id: 1, Name: "事业合伙人"} // 默认设定为事业合伙人订单 258 + // 默认设定为事业合伙人订单
  259 + orderbase.PartnerCategory = domain.PartnerCategory{Id: 1, Name: "事业合伙人"}
255 orderbase.Compute() 260 orderbase.Compute()
256 err = orderBaseRepository.Save(&orderbase) 261 err = orderBaseRepository.Save(&orderbase)
257 if err != nil { 262 if err != nil {
@@ -6,8 +6,9 @@ import ( @@ -6,8 +6,9 @@ import (
6 ) 6 )
7 7
8 type SyncCallbackCommand struct { 8 type SyncCallbackCommand struct {
9 - //position:职位,department:部门,employee:员工,company:公司 9 + //模块:position:职位,department:部门,employee:员工,company:公司
10 Module string `json:"module"` 10 Module string `json:"module"`
  11 + //动作:
11 //add:添加,edit:编辑,delete删除,batchDelete:批量删除, 12 //add:添加,edit:编辑,delete删除,batchDelete:批量删除,
12 //setCompanyCharge:更改公司主管,batchForbid:批量禁用用户, 13 //setCompanyCharge:更改公司主管,batchForbid:批量禁用用户,
13 //batchRemove:批量更改用户部门,changeAdmin换管理员 14 //batchRemove:批量更改用户部门,changeAdmin换管理员
@@ -8,14 +8,14 @@ var LOG_LEVEL = "debug" @@ -8,14 +8,14 @@ var LOG_LEVEL = "debug"
8 var LOG_File = "./logs/partnermg.log" 8 var LOG_File = "./logs/partnermg.log"
9 9
10 var ( 10 var (
11 - UCENTER_HOST = "https://suplus-ucenter-dev.fjmaimaimai.com" //统一用户中心地址 11 + UCENTER_HOST = "https://suplus-ucenter-test.fjmaimaimai.com" //统一用户中心地址
12 UCENTER_SECRET = "cykbjnfqgctn" 12 UCENTER_SECRET = "cykbjnfqgctn"
13 UCENTER_APP_KEY = "39aefef9e22744a3b2d2d3791824ae7b" 13 UCENTER_APP_KEY = "39aefef9e22744a3b2d2d3791824ae7b"
14 UCENTER_CHECK_ALT = "rsF0pL!6DwjBO735" 14 UCENTER_CHECK_ALT = "rsF0pL!6DwjBO735"
15 ) 15 )
16 16
17 var ( 17 var (
18 - BUSINESS_ADMIN_HOST = "http://suplus-business-admin-dev.fjmaimaimai.com" //企业平台的地址 18 + BUSINESS_ADMIN_HOST = "http://suplus-business-admin-test.fjmaimaimai.com" //企业平台的地址
19 ) 19 )
20 20
21 func init() { 21 func init() {
@@ -34,9 +34,7 @@ func init() { @@ -34,9 +34,7 @@ func init() {
34 if os.Getenv("UCENTER_CHECK_ALT") != "" { 34 if os.Getenv("UCENTER_CHECK_ALT") != "" {
35 UCENTER_CHECK_ALT = os.Getenv("UCENTER_CHECK_ALT") 35 UCENTER_CHECK_ALT = os.Getenv("UCENTER_CHECK_ALT")
36 } 36 }
37 -  
38 if os.Getenv("BUSINESS_ADMIN_HOST") != "" { 37 if os.Getenv("BUSINESS_ADMIN_HOST") != "" {
39 BUSINESS_ADMIN_HOST = os.Getenv("BUSINESS_ADMIN_HOST") 38 BUSINESS_ADMIN_HOST = os.Getenv("BUSINESS_ADMIN_HOST")
40 } 39 }
41 -  
42 } 40 }
@@ -14,7 +14,7 @@ var KafkaCfg KafkaConfig @@ -14,7 +14,7 @@ var KafkaCfg KafkaConfig
14 14
15 func init() { 15 func init() {
16 KafkaCfg = KafkaConfig{ 16 KafkaCfg = KafkaConfig{
17 - Servers: []string{""}, 17 + Servers: []string{"127.0.0.1:9092"},
18 ConsumerId: "partnermg_local", 18 ConsumerId: "partnermg_local",
19 } 19 }
20 if os.Getenv("KAFKA_HOST") != "" { 20 if os.Getenv("KAFKA_HOST") != "" {
@@ -2,11 +2,11 @@ package constant @@ -2,11 +2,11 @@ package constant
2 2
3 import "os" 3 import "os"
4 4
5 -var POSTGRESQL_DB_NAME = "partner_dev" 5 +var POSTGRESQL_DB_NAME = "partner_test"
6 var POSTGRESQL_USER = "postgres" 6 var POSTGRESQL_USER = "postgres"
7 -var POSTGRESQL_PASSWORD = "eagle1010"  
8 -var POSTGRESQL_HOST = "114.55.200.59"  
9 -var POSTGRESQL_PORT = "31543" 7 +var POSTGRESQL_PASSWORD = "1993618jack" // eagle1010
  8 +var POSTGRESQL_HOST = "127.0.0.1" // 114.55.200.59
  9 +var POSTGRESQL_PORT = "5432" // 31543
10 var DISABLE_CREATE_TABLE = true 10 var DISABLE_CREATE_TABLE = true
11 var DISABLE_SQL_GENERATE_PRINT = false 11 var DISABLE_SQL_GENERATE_PRINT = false
12 12
@@ -9,7 +9,7 @@ import ( @@ -9,7 +9,7 @@ import (
9 const ( 9 const (
10 OrderReal = iota + 1 //实发订单 10 OrderReal = iota + 1 //实发订单
11 OrderIntention //意向订单 11 OrderIntention //意向订单
12 - OrderTypeBestShop //来自小程序海鲜干货的订单 12 + OrderTypeBestShop //来自小程序香米的订单
13 ) 13 )
14 14
15 func GetOrderBaseTypeName(orderType int) string { 15 func GetOrderBaseTypeName(orderType int) string {
@@ -114,7 +114,7 @@ type OrderBase struct { @@ -114,7 +114,7 @@ type OrderBase struct {
114 DataFrom OrderDataFrom `json:"dataFrom"` 114 DataFrom OrderDataFrom `json:"dataFrom"`
115 //备注 115 //备注
116 Remark OrderBaseRemark `json:"remark"` 116 Remark OrderBaseRemark `json:"remark"`
117 - 117 + //合伙人类型
118 PartnerCategory PartnerCategory `json:"partnerCategory"` 118 PartnerCategory PartnerCategory `json:"partnerCategory"`
119 } 119 }
120 120
@@ -182,32 +182,41 @@ func (order *OrderBase) AddGoods(goods []OrderGood) { @@ -182,32 +182,41 @@ func (order *OrderBase) AddGoods(goods []OrderGood) {
182 order.Compute() 182 order.Compute()
183 } 183 }
184 184
185 -func (order *OrderBase) ModifyGoodNumber(goodid int64, number int64) {  
186 - for i := range order.Goods {  
187 - if order.Goods[i].Id != goodid {  
188 - continue  
189 - }  
190 - // thisGood := order.Goods[i] 185 +// func (order *OrderBase) ModifyGoodNumber(goodid int64, number int64) {
  186 +// for i := range order.Goods {
  187 +// if order.Goods[i].Id != goodid {
  188 +// continue
  189 +// }
  190 +// // thisGood := order.Goods[i]
191 191
192 - }  
193 - order.Compute()  
194 -} 192 +// }
  193 +// order.Compute()
  194 +// }
195 195
196 //Compute 数据汇总核算 196 //Compute 数据汇总核算
197 func (order *OrderBase) Compute() error { 197 func (order *OrderBase) Compute() error {
198 planPartnerBonus := decimal.NewFromFloat(0) 198 planPartnerBonus := decimal.NewFromFloat(0)
199 planOrderAmount := decimal.NewFromFloat(0) 199 planOrderAmount := decimal.NewFromFloat(0)
200 var ( 200 var (
201 - planOrderCount int = 0  
202 - useOrderCount int = 0 201 + //预计的货品总数,不包含调整后的值
  202 + planOrderCount int = 0
  203 + //调整后的货品总数,混合相加计算预计值和调整值中的一个,优先取调整值计算
  204 + useOrderCount int = 0
  205 + //订单的货品列表中是否存在调整货品数量
203 HasUseOrderCount bool = false 206 HasUseOrderCount bool = false
204 ) 207 )
  208 + //调整后的合伙人分红,混合相加计算预计值和调整值中的一个,优先取调整值计算
205 usePartnerBonus := decimal.NewFromFloat(0) 209 usePartnerBonus := decimal.NewFromFloat(0)
  210 + //订单的货品列表中是否存在调整的合伙人分红
206 var hasUsePartnerBonus bool = false 211 var hasUsePartnerBonus bool = false
  212 + //调整后的订单总额,混合相加计算预计值和调整值中的一个,优先取调整值计算
207 useOrderAmount := decimal.NewFromFloat(0) 213 useOrderAmount := decimal.NewFromFloat(0)
208 var hasUseOrderAmount bool = false 214 var hasUseOrderAmount bool = false
  215 + //已支付分红
209 partnerBonusHas := decimal.NewFromFloat(0) 216 partnerBonusHas := decimal.NewFromFloat(0)
  217 + //未支付分红
210 partnerBonusNot := decimal.NewFromFloat(0) 218 partnerBonusNot := decimal.NewFromFloat(0)
  219 + //分红支出
211 partnerBonusExpense := decimal.NewFromFloat(0) 220 partnerBonusExpense := decimal.NewFromFloat(0)
212 //初始订单的支付状态 221 //初始订单的支付状态
213 order.BonusStatus = OrderGoodWaitPay 222 order.BonusStatus = OrderGoodWaitPay
@@ -215,14 +224,20 @@ func (order *OrderBase) Compute() error { @@ -215,14 +224,20 @@ func (order *OrderBase) Compute() error {
215 for i := range order.Goods { 224 for i := range order.Goods {
216 if order.Goods[i].BonusStatus == OrderGoodHasPay { 225 if order.Goods[i].BonusStatus == OrderGoodHasPay {
217 //确定订单的支付状态 226 //确定订单的支付状态
  227 + //订单的货品列表中“存在”支付状态的为已支付,则整体订单设定为已支付状态
218 order.BonusStatus = OrderGoodHasPay 228 order.BonusStatus = OrderGoodHasPay
219 } 229 }
  230 + //计算预计的合伙人分红,不含调整的值
220 planPartnerBonus = planPartnerBonus.Add(decimal.NewFromFloat(order.Goods[i].GoodCompute.PlanPartnerBonus)) 231 planPartnerBonus = planPartnerBonus.Add(decimal.NewFromFloat(order.Goods[i].GoodCompute.PlanPartnerBonus))
  232 + //计算预计的订单总金额,不含调整的值
221 planOrderAmount = planOrderAmount.Add(decimal.NewFromFloat(order.Goods[i].GoodCompute.PlanAmount)) 233 planOrderAmount = planOrderAmount.Add(decimal.NewFromFloat(order.Goods[i].GoodCompute.PlanAmount))
  234 + //计算预计的订单中货品总数,不含调整的值
222 planOrderCount += order.Goods[i].PlanGoodNumber 235 planOrderCount += order.Goods[i].PlanGoodNumber
  236 + //获取调整货品调整后(数量)的总金额,
223 goodUseAmount := decimal.NewFromFloat(order.Goods[i].GoodCompute.UseAmount) 237 goodUseAmount := decimal.NewFromFloat(order.Goods[i].GoodCompute.UseAmount)
  238 +
224 if goodUseAmount.GreaterThanOrEqual(decimal.NewFromFloat(0)) { 239 if goodUseAmount.GreaterThanOrEqual(decimal.NewFromFloat(0)) {
225 - //调整值非负值得情况 240 + //调整后货品总金额,非负值(大于等于0)的情况
226 hasUseOrderAmount = true 241 hasUseOrderAmount = true
227 useOrderAmount = useOrderAmount.Add(goodUseAmount) 242 useOrderAmount = useOrderAmount.Add(goodUseAmount)
228 } else { 243 } else {
@@ -230,12 +245,14 @@ func (order *OrderBase) Compute() error { @@ -230,12 +245,14 @@ func (order *OrderBase) Compute() error {
230 } 245 }
231 goodUsePartnerBonus := decimal.NewFromFloat(order.Goods[i].GoodCompute.UsePartnerBonus) 246 goodUsePartnerBonus := decimal.NewFromFloat(order.Goods[i].GoodCompute.UsePartnerBonus)
232 if goodUsePartnerBonus.GreaterThanOrEqual(decimal.NewFromFloat(0)) { 247 if goodUsePartnerBonus.GreaterThanOrEqual(decimal.NewFromFloat(0)) {
  248 + //货品中存在调整后的合伙人分红,即调整大于等于0
233 hasUsePartnerBonus = true 249 hasUsePartnerBonus = true
234 usePartnerBonus = usePartnerBonus.Add(goodUsePartnerBonus) 250 usePartnerBonus = usePartnerBonus.Add(goodUsePartnerBonus)
235 } else { 251 } else {
236 usePartnerBonus = usePartnerBonus.Add(decimal.NewFromFloat(order.Goods[i].GoodCompute.PlanPartnerBonus)) 252 usePartnerBonus = usePartnerBonus.Add(decimal.NewFromFloat(order.Goods[i].GoodCompute.PlanPartnerBonus))
237 } 253 }
238 if order.Goods[i].UseGoodNumber >= 0 { 254 if order.Goods[i].UseGoodNumber >= 0 {
  255 + //货品中存在调整后的数量,调整值大于等于0
239 HasUseOrderCount = true 256 HasUseOrderCount = true
240 useOrderCount += order.Goods[i].UseGoodNumber 257 useOrderCount += order.Goods[i].UseGoodNumber
241 } else { 258 } else {
@@ -256,6 +273,7 @@ func (order *OrderBase) Compute() error { @@ -256,6 +273,7 @@ func (order *OrderBase) Compute() error {
256 if hasUsePartnerBonus { 273 if hasUsePartnerBonus {
257 order.OrderCompute.UsePartnerBonus, _ = usePartnerBonus.Round(2).BigFloat().Float64() 274 order.OrderCompute.UsePartnerBonus, _ = usePartnerBonus.Round(2).BigFloat().Float64()
258 } else { 275 } else {
  276 + //订单中的货品列表中合伙人分成没有调整值的情况下,对订单的调整值设置为负值用以标识
259 order.OrderCompute.UsePartnerBonus = -1 277 order.OrderCompute.UsePartnerBonus = -1
260 } 278 }
261 if hasUseOrderAmount { 279 if hasUseOrderAmount {
@@ -266,6 +284,7 @@ func (order *OrderBase) Compute() error { @@ -266,6 +284,7 @@ func (order *OrderBase) Compute() error {
266 Div(decimal.NewFromInt(100)). 284 Div(decimal.NewFromInt(100)).
267 Round(2).BigFloat().Float64() 285 Round(2).BigFloat().Float64()
268 } else { 286 } else {
  287 + //订单中的货品列表中货品总金额没有调整值的情况下,对订单的调整值设置为负值用以标识
269 order.OrderCompute.UseOrderAmount = -1 288 order.OrderCompute.UseOrderAmount = -1
270 order.OrderCompute.SalesmanBonus, _ = planOrderAmount. 289 order.OrderCompute.SalesmanBonus, _ = planOrderAmount.
271 Mul(decimal.NewFromFloat(order.SalesmanBonusPercent)). 290 Mul(decimal.NewFromFloat(order.SalesmanBonusPercent)).
@@ -70,7 +70,7 @@ type OrderGood struct { @@ -70,7 +70,7 @@ type OrderGood struct {
70 UseGoodNumber int `json:"useGoodNumber"` 70 UseGoodNumber int `json:"useGoodNumber"`
71 //货品单价 71 //货品单价
72 Price float64 `json:"price"` 72 Price float64 `json:"price"`
73 - //合伙人分红比例 73 + //合伙人分红比例 比如12.7等同于12.7%,使用负值表示分红比例未进行设置
74 PartnerBonusPercent float64 `json:"partnerBonusPercent"` 74 PartnerBonusPercent float64 `json:"partnerBonusPercent"`
75 //分红支付状态 75 //分红支付状态
76 BonusStatus int `json:"bonusStatus"` 76 BonusStatus int `json:"bonusStatus"`
@@ -87,6 +87,20 @@ type OrderGood struct { @@ -87,6 +87,20 @@ type OrderGood struct {
87 DataFrom OrderDataFrom `json:"data_from"` 87 DataFrom OrderDataFrom `json:"data_from"`
88 } 88 }
89 89
  90 +//NewOrderGood 初始值设定
  91 +func NewOrderGood() OrderGood {
  92 + return OrderGood{
  93 + UseGoodNumber: -1,
  94 + BonusStatus: OrderGoodWaitPay,
  95 + PartnerBonusPercent: -1,
  96 + GoodCompute: GoodCompute{
  97 + UsePartnerBonus: -1,
  98 + UseAmount: -1,
  99 + },
  100 + CurrentBonusStatus: OrderGoodBonusWaitPay{},
  101 + }
  102 +}
  103 +
90 //GetCurrentGoodNumber 获取当前的商品数量 104 //GetCurrentGoodNumber 获取当前的商品数量
91 func (good OrderGood) GetCurrentGoodNumber() int { 105 func (good OrderGood) GetCurrentGoodNumber() int {
92 if good.UseGoodNumber >= 0 { 106 if good.UseGoodNumber >= 0 {
@@ -111,7 +125,7 @@ func (good OrderGood) GetCurrentPartnerBonus() float64 { @@ -111,7 +125,7 @@ func (good OrderGood) GetCurrentPartnerBonus() float64 {
111 return good.GoodCompute.PlanPartnerBonus 125 return good.GoodCompute.PlanPartnerBonus
112 } 126 }
113 127
114 -//GetCurrentAmount 获取当前的商品合伙人分红 128 +//ModifyOrderGoodNumber 修改货品数量
115 func (good *OrderGood) ModifyOrderGoodNumber(number int, orderType int) error { 129 func (good *OrderGood) ModifyOrderGoodNumber(number int, orderType int) error {
116 if good.PlanGoodNumber < number { 130 if good.PlanGoodNumber < number {
117 return fmt.Errorf("修改数量不能大于初始值:%d", good.PlanGoodNumber) 131 return fmt.Errorf("修改数量不能大于初始值:%d", good.PlanGoodNumber)
@@ -120,6 +134,7 @@ func (good *OrderGood) ModifyOrderGoodNumber(number int, orderType int) error { @@ -120,6 +134,7 @@ func (good *OrderGood) ModifyOrderGoodNumber(number int, orderType int) error {
120 return err 134 return err
121 } 135 }
122 136
  137 +//ModifyPertnerBonusPercent 修改货品的分红比例
123 func (good *OrderGood) ModifyPertnerBonusPercent(percent float64, orderType int) error { 138 func (good *OrderGood) ModifyPertnerBonusPercent(percent float64, orderType int) error {
124 err := good.CurrentBonusStatus.ModifyPertnerBonusPercent(good, percent, orderType) 139 err := good.CurrentBonusStatus.ModifyPertnerBonusPercent(good, percent, orderType)
125 return err 140 return err
@@ -162,6 +177,7 @@ type OrderGoodBonusHasPay struct{} @@ -162,6 +177,7 @@ type OrderGoodBonusHasPay struct{}
162 177
163 var _ OrderGoodBonusStatus = (*OrderGoodBonusHasPay)(nil) 178 var _ OrderGoodBonusStatus = (*OrderGoodBonusHasPay)(nil)
164 179
  180 +//WartPayPartnerBonus 货品的支付状态从“待支付”状态变更为“待支付”
165 func (waitPay OrderGoodBonusWaitPay) WartPayPartnerBonus(good *OrderGood) error { 181 func (waitPay OrderGoodBonusWaitPay) WartPayPartnerBonus(good *OrderGood) error {
166 good.GoodCompute.PartnerBonusExpense = 0 182 good.GoodCompute.PartnerBonusExpense = 0
167 good.GoodCompute.PartnerBonusHas = 0 183 good.GoodCompute.PartnerBonusHas = 0
@@ -178,6 +194,7 @@ func (waitPay OrderGoodBonusWaitPay) WartPayPartnerBonus(good *OrderGood) error @@ -178,6 +194,7 @@ func (waitPay OrderGoodBonusWaitPay) WartPayPartnerBonus(good *OrderGood) error
178 return nil 194 return nil
179 } 195 }
180 196
  197 +//PayPartnerBonus 货品的支付状态从“待支付”状态变更为“已支付”
181 func (waitPay OrderGoodBonusWaitPay) PayPartnerBonus(good *OrderGood) error { 198 func (waitPay OrderGoodBonusWaitPay) PayPartnerBonus(good *OrderGood) error {
182 //待支付状态转支付时 199 //待支付状态转支付时
183 //合伙人已收收分红等于合伙人应收分红(或者调整的) 200 //合伙人已收收分红等于合伙人应收分红(或者调整的)
@@ -196,6 +213,7 @@ func (waitPay OrderGoodBonusWaitPay) PayPartnerBonus(good *OrderGood) error { @@ -196,6 +213,7 @@ func (waitPay OrderGoodBonusWaitPay) PayPartnerBonus(good *OrderGood) error {
196 return nil 213 return nil
197 } 214 }
198 215
  216 +//PayPartnerBonus 货品的支付状态从“已支付”状态变更为“已支付”
199 func (hasPay OrderGoodBonusHasPay) PayPartnerBonus(good *OrderGood) error { 217 func (hasPay OrderGoodBonusHasPay) PayPartnerBonus(good *OrderGood) error {
200 //已支付的值保持不变 218 //已支付的值保持不变
201 //未支付的值保持不变 219 //未支付的值保持不变
@@ -210,10 +228,12 @@ func (hasPay OrderGoodBonusHasPay) PayPartnerBonus(good *OrderGood) error { @@ -210,10 +228,12 @@ func (hasPay OrderGoodBonusHasPay) PayPartnerBonus(good *OrderGood) error {
210 return nil 228 return nil
211 } 229 }
212 230
  231 +//WartPayPartnerBonus 货品的支付状态从“已支付”状态变更为“待支付”
213 func (hasPay OrderGoodBonusHasPay) WartPayPartnerBonus(good *OrderGood) error { 232 func (hasPay OrderGoodBonusHasPay) WartPayPartnerBonus(good *OrderGood) error {
214 return errors.New("已支付的货单不能将状态回退为待支付") 233 return errors.New("已支付的货单不能将状态回退为待支付")
215 } 234 }
216 235
  236 +//ModifyOrderGoodNumber 货品的支付状态为“已支付”状态变时,修改货品数量
217 func (hasPay OrderGoodBonusHasPay) ModifyOrderGoodNumber(good *OrderGood, number int, orderType int) error { 237 func (hasPay OrderGoodBonusHasPay) ModifyOrderGoodNumber(good *OrderGood, number int, orderType int) error {
218 //规则描述: 238 //规则描述:
219 //实际自建订单(orderType==1),已支付分红状态下“可以”修改货品数量 239 //实际自建订单(orderType==1),已支付分红状态下“可以”修改货品数量
@@ -233,6 +253,7 @@ func (hasPay OrderGoodBonusHasPay) ModifyOrderGoodNumber(good *OrderGood, number @@ -233,6 +253,7 @@ func (hasPay OrderGoodBonusHasPay) ModifyOrderGoodNumber(good *OrderGood, number
233 return nil 253 return nil
234 } 254 }
235 255
  256 +//ModifyOrderGoodNumber 货品的支付状态为“待支付”状态变时,修改货品数量
236 func (waitPay OrderGoodBonusWaitPay) ModifyOrderGoodNumber(good *OrderGood, number int, orderType int) error { 257 func (waitPay OrderGoodBonusWaitPay) ModifyOrderGoodNumber(good *OrderGood, number int, orderType int) error {
237 //规则描述: 258 //规则描述:
238 //实际自建订单(orderType==1),未支付分红状态下“可以”修改货品数量 259 //实际自建订单(orderType==1),未支付分红状态下“可以”修改货品数量
@@ -247,6 +268,7 @@ func (waitPay OrderGoodBonusWaitPay) ModifyOrderGoodNumber(good *OrderGood, numb @@ -247,6 +268,7 @@ func (waitPay OrderGoodBonusWaitPay) ModifyOrderGoodNumber(good *OrderGood, numb
247 return nil 268 return nil
248 } 269 }
249 270
  271 +//ModifyPertnerBonusPercent 货品的支付状态为“待支付”状态变时,修改货品合伙人分红比例
250 func (waitPay OrderGoodBonusWaitPay) ModifyPertnerBonusPercent(good *OrderGood, percent float64, orderType int) error { 272 func (waitPay OrderGoodBonusWaitPay) ModifyPertnerBonusPercent(good *OrderGood, percent float64, orderType int) error {
251 //规则描述: 273 //规则描述:
252 //实际自建订单(orderType==1),未支付分红状态下“不可以”修改合伙人分红比例 274 //实际自建订单(orderType==1),未支付分红状态下“不可以”修改合伙人分红比例
@@ -276,20 +298,6 @@ func (hasPay OrderGoodBonusHasPay) ModifyPertnerBonusPercent(good *OrderGood, pe @@ -276,20 +298,6 @@ func (hasPay OrderGoodBonusHasPay) ModifyPertnerBonusPercent(good *OrderGood, pe
276 return errors.New("已支付分红的货品订单,不能修改合伙人分红比例") 298 return errors.New("已支付分红的货品订单,不能修改合伙人分红比例")
277 } 299 }
278 300
279 -//NewOrderGood 初始值设定  
280 -func NewOrderGood() OrderGood {  
281 - return OrderGood{  
282 - UseGoodNumber: -1,  
283 - BonusStatus: OrderGoodWaitPay,  
284 - PartnerBonusPercent: -1,  
285 - GoodCompute: GoodCompute{  
286 - UsePartnerBonus: -1,  
287 - UseAmount: -1,  
288 - },  
289 - CurrentBonusStatus: OrderGoodBonusWaitPay{},  
290 - }  
291 -}  
292 -  
293 //Compute 数据汇总核算 301 //Compute 数据汇总核算
294 func (good *OrderGood) Compute() error { 302 func (good *OrderGood) Compute() error {
295 //计算预计货品总值 303 //计算预计货品总值
@@ -299,25 +307,28 @@ func (good *OrderGood) Compute() error { @@ -299,25 +307,28 @@ func (good *OrderGood) Compute() error {
299 if good.PlanGoodNumber < 0 { 307 if good.PlanGoodNumber < 0 {
300 planGoodNumber = 0 308 planGoodNumber = 0
301 } 309 }
302 - planamount := price.Mul(decimal.NewFromInt(int64(planGoodNumber))) //price*planGoodNumber 310 + //计算预计货品总值(planamount), 货品单价*预计货品数量(price*planGoodNumber)
  311 + planamount := price.Mul(decimal.NewFromInt(int64(planGoodNumber)))
303 var partnerBonusPercent float64 312 var partnerBonusPercent float64
304 if good.PartnerBonusPercent < 0 { 313 if good.PartnerBonusPercent < 0 {
  314 + //判断合伙人分成比例是否设置,若未设置则按照 0 来计算分成
305 partnerBonusPercent = 0 315 partnerBonusPercent = 0
306 } else { 316 } else {
307 partnerBonusPercent = good.PartnerBonusPercent 317 partnerBonusPercent = good.PartnerBonusPercent
308 } 318 }
309 - //price*useGoodNumber 319 + //计算预计合伙人分红(planPartnerBonus), 预计货品总值*合伙人分成比例/100(planamount*partnerBonusPercent/100)
310 planPartnerBonus := planamount.Mul(decimal.NewFromFloat(partnerBonusPercent)).Div(decimal.NewFromInt(100)) //price*planGoodNumber*PartnerBonusPercent 320 planPartnerBonus := planamount.Mul(decimal.NewFromFloat(partnerBonusPercent)).Div(decimal.NewFromInt(100)) //price*planGoodNumber*PartnerBonusPercent
  321 + //货品预计总值
311 good.GoodCompute.PlanAmount, _ = planamount.Round(2).BigFloat().Float64() 322 good.GoodCompute.PlanAmount, _ = planamount.Round(2).BigFloat().Float64()
312 good.GoodCompute.PlanPartnerBonus, _ = planPartnerBonus.Round(2).BigFloat().Float64() 323 good.GoodCompute.PlanPartnerBonus, _ = planPartnerBonus.Round(2).BigFloat().Float64()
313 if good.UseGoodNumber < 0 { 324 if good.UseGoodNumber < 0 {
314 - //没有出现数量调整 325 + //没有出现数量调整,使用负值进行标记
315 good.GoodCompute.UsePartnerBonus = -1 326 good.GoodCompute.UsePartnerBonus = -1
316 good.GoodCompute.UseAmount = -1 327 good.GoodCompute.UseAmount = -1
317 } else { 328 } else {
318 //计算调整后的货品总值 329 //计算调整后的货品总值
319 - //计算调整后的合伙人分红  
320 - useamount := price.Mul(decimal.NewFromInt(int64(good.UseGoodNumber))) //price*useGoodNumber/price*useGoodNumber 330 + useamount := price.Mul(decimal.NewFromInt(int64(good.UseGoodNumber)))
  331 + //计算调整后的合伙人分红 //price*useGoodNumber/price*useGoodNumber
321 usePartnerBonus := useamount.Mul(decimal.NewFromFloat(partnerBonusPercent)).Div(decimal.NewFromInt(100)) //price*useGoodNumber*PartnerBonusPercent 332 usePartnerBonus := useamount.Mul(decimal.NewFromFloat(partnerBonusPercent)).Div(decimal.NewFromInt(100)) //price*useGoodNumber*PartnerBonusPercent
322 good.GoodCompute.UsePartnerBonus, _ = usePartnerBonus.Round(2).BigFloat().Float64() 333 good.GoodCompute.UsePartnerBonus, _ = usePartnerBonus.Round(2).BigFloat().Float64()
323 good.GoodCompute.UseAmount, _ = useamount.Round(2).BigFloat().Float64() 334 good.GoodCompute.UseAmount, _ = useamount.Round(2).BigFloat().Float64()
@@ -6,6 +6,8 @@ type PartnerCategory struct { @@ -6,6 +6,8 @@ type PartnerCategory struct {
6 Id int64 `json:"id"` 6 Id int64 `json:"id"`
7 // 名称 7 // 名称
8 Name string `json:"name,omitempty"` 8 Name string `json:"name,omitempty"`
  9 + // 合伙人编码
  10 + Code string `json:"code"`
9 } 11 }
10 12
11 type PartnerCategoryFindQuery struct { 13 type PartnerCategoryFindQuery struct {
@@ -48,6 +48,8 @@ type PartnerInfo struct { @@ -48,6 +48,8 @@ type PartnerInfo struct {
48 PartnerCategory int `json:"partnerCategory"` 48 PartnerCategory int `json:"partnerCategory"`
49 //公司id 49 //公司id
50 CompanyId int64 `json:"companyId"` 50 CompanyId int64 `json:"companyId"`
  51 + //备注
  52 + Remark string `json:"remark"`
51 } 53 }
52 54
53 func (p *PartnerInfo) IsUsable() bool { 55 func (p *PartnerInfo) IsUsable() bool {
@@ -72,11 +74,13 @@ type PartnerFindQuery struct { @@ -72,11 +74,13 @@ type PartnerFindQuery struct {
72 PartnerName string //合伙人姓名 74 PartnerName string //合伙人姓名
73 CompanyId int64 75 CompanyId int64
74 Ids []int64 76 Ids []int64
  77 + PartnerType []*PartnerCategory
75 } 78 }
76 79
77 type PartnerInfoRepository interface { 80 type PartnerInfoRepository interface {
78 Save(dm *PartnerInfo) error 81 Save(dm *PartnerInfo) error
79 FindOne(queryOptions PartnerFindOneQuery) (*PartnerInfo, error) 82 FindOne(queryOptions PartnerFindOneQuery) (*PartnerInfo, error)
80 Find(queryOptions PartnerFindQuery) ([]PartnerInfo, error) 83 Find(queryOptions PartnerFindQuery) ([]PartnerInfo, error)
  84 + Remove(Id int64) error
81 CountAll(queryOptions PartnerFindQuery) (int, error) 85 CountAll(queryOptions PartnerFindQuery) (int, error)
82 } 86 }
@@ -2,7 +2,7 @@ package dao @@ -2,7 +2,7 @@ package dao
2 2
3 import ( 3 import (
4 "fmt" 4 "fmt"
5 - 5 + "github.com/go-pg/pg/v10"
6 "gitlab.fjmaimaimai.com/mmm-go/partnermg/pkg/infrastructure/pg/models" 6 "gitlab.fjmaimaimai.com/mmm-go/partnermg/pkg/infrastructure/pg/models"
7 "gitlab.fjmaimaimai.com/mmm-go/partnermg/pkg/infrastructure/pg/transaction" 7 "gitlab.fjmaimaimai.com/mmm-go/partnermg/pkg/infrastructure/pg/transaction"
8 ) 8 )
@@ -28,7 +28,6 @@ func (dao PartnerInfoDao) PartnerAccountExist(account string, companyId int64) ( @@ -28,7 +28,6 @@ func (dao PartnerInfoDao) PartnerAccountExist(account string, companyId int64) (
28 Where("account=?", account). 28 Where("account=?", account).
29 Where("company_id=?", companyId). 29 Where("company_id=?", companyId).
30 Exists() 30 Exists()
31 -  
32 return ok, err 31 return ok, err
33 } 32 }
34 33
@@ -42,3 +41,21 @@ func (dao PartnerInfoDao) UpdatePartnerStatus(ids []int64, companyId int64, stat @@ -42,3 +41,21 @@ func (dao PartnerInfoDao) UpdatePartnerStatus(ids []int64, companyId int64, stat
42 Update() 41 Update()
43 return err 42 return err
44 } 43 }
  44 +
  45 +/**
  46 + * @Author SteveChan
  47 + * @Description // 编号查重
  48 + * @Date 17:55 2020/12/28
  49 + * @Param
  50 + * @return
  51 + **/
  52 +func (dao PartnerInfoDao) PartnerCodeExist(categoryId int64, code string, companyId int64, id int64) (bool, error) {
  53 + tx := dao.transactionContext.PgDd
  54 + m := &models.PartnerInfo{}
  55 + ok, err := tx.Model(m).
  56 + Where(`partner_category_infos@> '[{"id":?,"code":?}]'`, categoryId, pg.Ident(code)).
  57 + Where("company_id=?", companyId).
  58 + Where("id <> ?", id).
  59 + Exists()
  60 + return ok, err
  61 +}
@@ -35,4 +35,5 @@ type OrderBestshop struct { @@ -35,4 +35,5 @@ type OrderBestshop struct {
35 //是否将数据同步到 order_base ,order_good 35 //是否将数据同步到 order_base ,order_good
36 IsCopy bool `pg:",use_zero"` 36 IsCopy bool `pg:",use_zero"`
37 CompanyId int64 37 CompanyId int64
  38 + OrderArea string
38 } 39 }
@@ -7,4 +7,6 @@ type PartnerCategoryInfo struct { @@ -7,4 +7,6 @@ type PartnerCategoryInfo struct {
7 Id int64 7 Id int64
8 // 名称 8 // 名称
9 Name string 9 Name string
  10 + // 合伙人编码
  11 + Code string
10 } 12 }
@@ -36,6 +36,8 @@ type PartnerInfo struct { @@ -36,6 +36,8 @@ type PartnerInfo struct {
36 PartnerCategoryInfos []domain.PartnerCategory 36 PartnerCategoryInfos []domain.PartnerCategory
37 //公司id 37 //公司id
38 CompanyId int64 38 CompanyId int64
  39 + //备注
  40 + Remark string
39 } 41 }
40 42
41 var _ pg.BeforeUpdateHook = (*PartnerInfo)(nil) 43 var _ pg.BeforeUpdateHook = (*PartnerInfo)(nil)
@@ -43,6 +43,7 @@ func (respository OrderBestshopRepository) transformPgModelToDomainModel(orderMo @@ -43,6 +43,7 @@ func (respository OrderBestshopRepository) transformPgModelToDomainModel(orderMo
43 PartnerId: orderModel.PartnerId, 43 PartnerId: orderModel.PartnerId,
44 IsCopy: orderModel.IsCopy, 44 IsCopy: orderModel.IsCopy,
45 CompanyId: orderModel.CompanyId, 45 CompanyId: orderModel.CompanyId,
  46 + OrderArea: orderModel.OrderArea,
46 }, nil 47 }, nil
47 } 48 }
48 49
@@ -65,6 +66,7 @@ func (respository OrderBestshopRepository) Add(order *domain.OrderBestShop) erro @@ -65,6 +66,7 @@ func (respository OrderBestshopRepository) Add(order *domain.OrderBestShop) erro
65 PartnerId: order.PartnerId, 66 PartnerId: order.PartnerId,
66 IsCopy: order.IsCopy, 67 IsCopy: order.IsCopy,
67 CompanyId: order.CompanyId, 68 CompanyId: order.CompanyId,
  69 + OrderArea: order.OrderArea,
68 } 70 }
69 _, err := tx.Model(&m).Insert() 71 _, err := tx.Model(&m).Insert()
70 order.Id = m.Id 72 order.Id = m.Id
@@ -91,6 +93,7 @@ func (respository OrderBestshopRepository) Edit(order *domain.OrderBestShop) err @@ -91,6 +93,7 @@ func (respository OrderBestshopRepository) Edit(order *domain.OrderBestShop) err
91 PartnerId: order.PartnerId, 93 PartnerId: order.PartnerId,
92 IsCopy: order.IsCopy, 94 IsCopy: order.IsCopy,
93 CompanyId: order.CompanyId, 95 CompanyId: order.CompanyId,
  96 + OrderArea: order.OrderArea,
94 } 97 }
95 _, err := tx.Model(&m).Where("id=?", order.Id).Update() 98 _, err := tx.Model(&m).Where("id=?", order.Id).Update()
96 order.Id = m.Id 99 order.Id = m.Id
@@ -12,21 +12,6 @@ type PartnerCategoryRepository struct { @@ -12,21 +12,6 @@ type PartnerCategoryRepository struct {
12 transactionContext *transaction.TransactionContext 12 transactionContext *transaction.TransactionContext
13 } 13 }
14 14
15 -func (repository PartnerCategoryRepository) transformPgModelToDomainModel(m *models.PartnerCategoryInfo) (domain.PartnerCategory, error) {  
16 - pc := domain.PartnerCategory{  
17 - Id: m.Id,  
18 - Name: m.Name,  
19 - }  
20 - return pc, nil  
21 -}  
22 -  
23 -func NewPartnerCategoryRepository(transactionContext *transaction.TransactionContext) (*PartnerCategoryRepository, error) {  
24 - if transactionContext == nil {  
25 - return nil, fmt.Errorf("transactionContext参数不能为nil")  
26 - }  
27 - return &PartnerCategoryRepository{transactionContext: transactionContext}, nil  
28 -}  
29 -  
30 func (repository PartnerCategoryRepository) Find(queryOptions domain.PartnerCategoryFindQuery) (int, []domain.PartnerCategory, error) { 15 func (repository PartnerCategoryRepository) Find(queryOptions domain.PartnerCategoryFindQuery) (int, []domain.PartnerCategory, error) {
31 tx := repository.transactionContext.PgTx 16 tx := repository.transactionContext.PgTx
32 var ( 17 var (
@@ -48,3 +33,19 @@ func (repository PartnerCategoryRepository) Find(queryOptions domain.PartnerCate @@ -48,3 +33,19 @@ func (repository PartnerCategoryRepository) Find(queryOptions domain.PartnerCate
48 } 33 }
49 return cnt, partnerCategoryInfos, nil 34 return cnt, partnerCategoryInfos, nil
50 } 35 }
  36 +
  37 +func (repository PartnerCategoryRepository) transformPgModelToDomainModel(m *models.PartnerCategoryInfo) (domain.PartnerCategory, error) {
  38 + pc := domain.PartnerCategory{
  39 + Id: m.Id,
  40 + Name: m.Name,
  41 + Code: m.Code,
  42 + }
  43 + return pc, nil
  44 +}
  45 +
  46 +func NewPartnerCategoryRepository(transactionContext *transaction.TransactionContext) (*PartnerCategoryRepository, error) {
  47 + if transactionContext == nil {
  48 + return nil, fmt.Errorf("transactionContext参数不能为nil")
  49 + }
  50 + return &PartnerCategoryRepository{transactionContext: transactionContext}, nil
  51 +}
@@ -18,50 +18,18 @@ var ( @@ -18,50 +18,18 @@ var (
18 _ domain.PartnerInfoRepository = (*PartnerInfoRepository)(nil) 18 _ domain.PartnerInfoRepository = (*PartnerInfoRepository)(nil)
19 ) 19 )
20 20
21 -func (repository *PartnerInfoRepository) transformPgModelToDomainModel(partnerInfoModel *models.PartnerInfo) (domain.PartnerInfo, error) {  
22 - m := domain.PartnerInfo{  
23 - Partner: domain.Partner{  
24 - Id: partnerInfoModel.Id,  
25 - PartnerName: partnerInfoModel.PartnerName,  
26 - Account: partnerInfoModel.Account,  
27 - },  
28 - PartnerCategory: partnerInfoModel.PartnerCategory,  
29 - Password: partnerInfoModel.Password,  
30 - Status: partnerInfoModel.Status,  
31 - CreateAt: partnerInfoModel.CreateAt,  
32 - Salesman: partnerInfoModel.Salesman,  
33 - RegionInfo: partnerInfoModel.RegionInfo,  
34 - CooperateTime: partnerInfoModel.CooperateTime,  
35 - CompanyId: partnerInfoModel.CompanyId,  
36 - }  
37 - p := []domain.PartnerCategory{}  
38 - for _, v := range partnerInfoModel.PartnerCategoryInfos {  
39 - catagory := domain.PartnerCategory{  
40 - Id: v.Id,  
41 - }  
42 - p = append(p, catagory)  
43 - }  
44 - m.PartnerCategoryInfos = p  
45 - return m, nil  
46 -}  
47 -  
48 -func NewPartnerInfoRepository(transactionContext *transaction.TransactionContext) (*PartnerInfoRepository, error) {  
49 - if transactionContext == nil {  
50 - return nil, fmt.Errorf("transactionContext参数不能为nil")  
51 - }  
52 - return &PartnerInfoRepository{transactionContext: transactionContext}, nil  
53 -}  
54 -  
55 func (repository *PartnerInfoRepository) Save(dm *domain.PartnerInfo) error { 21 func (repository *PartnerInfoRepository) Save(dm *domain.PartnerInfo) error {
56 var ( 22 var (
57 err error 23 err error
58 tx = repository.transactionContext.PgTx 24 tx = repository.transactionContext.PgTx
59 ) 25 )
60 26
61 - categorys := []domain.PartnerCategory{} 27 + var categories []domain.PartnerCategory
62 for _, v := range dm.PartnerCategoryInfos { 28 for _, v := range dm.PartnerCategoryInfos {
63 - categorys = append(categorys, domain.PartnerCategory{  
64 - Id: v.Id, 29 + categories = append(categories, domain.PartnerCategory{
  30 + Id: v.Id,
  31 + Name: v.Name,
  32 + Code: v.Code,
65 }) 33 })
66 } 34 }
67 m := &models.PartnerInfo{ 35 m := &models.PartnerInfo{
@@ -75,7 +43,8 @@ func (repository *PartnerInfoRepository) Save(dm *domain.PartnerInfo) error { @@ -75,7 +43,8 @@ func (repository *PartnerInfoRepository) Save(dm *domain.PartnerInfo) error {
75 RegionInfo: dm.RegionInfo, 43 RegionInfo: dm.RegionInfo,
76 CooperateTime: dm.CooperateTime, 44 CooperateTime: dm.CooperateTime,
77 CompanyId: dm.CompanyId, 45 CompanyId: dm.CompanyId,
78 - PartnerCategoryInfos: categorys, 46 + PartnerCategoryInfos: categories,
  47 + Remark: dm.Remark,
79 } 48 }
80 if m.Id == 0 { 49 if m.Id == 0 {
81 err = tx.Insert(m) 50 err = tx.Insert(m)
@@ -86,7 +55,7 @@ func (repository *PartnerInfoRepository) Save(dm *domain.PartnerInfo) error { @@ -86,7 +55,7 @@ func (repository *PartnerInfoRepository) Save(dm *domain.PartnerInfo) error {
86 } else { 55 } else {
87 _, err = tx.Model(m).WherePK(). 56 _, err = tx.Model(m).WherePK().
88 Column("partner_name", "account", "password", "status", "partner_category", "salesman", 57 Column("partner_name", "account", "password", "status", "partner_category", "salesman",
89 - "region_info", "cooperate_time", "update_at", "partner_category_infos"). 58 + "region_info", "cooperate_time", "update_at", "partner_category_infos", "remark").
90 Update() 59 Update()
91 if err != nil { 60 if err != nil {
92 return err 61 return err
@@ -124,7 +93,7 @@ func (repository *PartnerInfoRepository) FindOne(queryOptions domain.PartnerFind @@ -124,7 +93,7 @@ func (repository *PartnerInfoRepository) FindOne(queryOptions domain.PartnerFind
124 93
125 func (repository *PartnerInfoRepository) Find(queryOption domain.PartnerFindQuery) ([]domain.PartnerInfo, error) { 94 func (repository *PartnerInfoRepository) Find(queryOption domain.PartnerFindQuery) ([]domain.PartnerInfo, error) {
126 db := repository.transactionContext.PgTx 95 db := repository.transactionContext.PgTx
127 - partnerModels := []models.PartnerInfo{} 96 + var partnerModels []models.PartnerInfo
128 query := db.Model(&partnerModels) 97 query := db.Model(&partnerModels)
129 if len(queryOption.PartnerName) > 0 { 98 if len(queryOption.PartnerName) > 0 {
130 query = query.Where("partner_name like ?", "%"+queryOption.PartnerName+"%") 99 query = query.Where("partner_name like ?", "%"+queryOption.PartnerName+"%")
@@ -159,7 +128,7 @@ func (repository *PartnerInfoRepository) Find(queryOption domain.PartnerFindQuer @@ -159,7 +128,7 @@ func (repository *PartnerInfoRepository) Find(queryOption domain.PartnerFindQuer
159 err error 128 err error
160 partnerReturn = make([]domain.PartnerInfo, 0) 129 partnerReturn = make([]domain.PartnerInfo, 0)
161 ) 130 )
162 - query = query.Order("id DESC") 131 + query = query.Order("create_at DESC")
163 err = query.Select() 132 err = query.Select()
164 if err != nil { 133 if err != nil {
165 return partnerReturn, err 134 return partnerReturn, err
@@ -174,7 +143,28 @@ func (repository *PartnerInfoRepository) Find(queryOption domain.PartnerFindQuer @@ -174,7 +143,28 @@ func (repository *PartnerInfoRepository) Find(queryOption domain.PartnerFindQuer
174 return partnerReturn, nil 143 return partnerReturn, nil
175 } 144 }
176 145
177 -func (repository PartnerInfoRepository) CountAll(queryOption domain.PartnerFindQuery) (int, error) { 146 +/**
  147 + * @Author SteveChan
  148 + * @Description // 移除合伙人
  149 + * @Date 15:33 2020/12/29
  150 + * @Param
  151 + * @return
  152 + **/
  153 +func (repository *PartnerInfoRepository) Remove(id int64) error {
  154 + var (
  155 + err error
  156 + tx = repository.transactionContext.PgTx
  157 + )
  158 + m := &models.PartnerInfo{
  159 + Id: id,
  160 + }
  161 + _, err = tx.Model(m).
  162 + Where("id=?", id).
  163 + Delete()
  164 + return err
  165 +}
  166 +
  167 +func (repository *PartnerInfoRepository) CountAll(queryOption domain.PartnerFindQuery) (int, error) {
178 db := repository.transactionContext.PgTx 168 db := repository.transactionContext.PgTx
179 partnerModels := models.PartnerInfo{} 169 partnerModels := models.PartnerInfo{}
180 query := db.Model(&partnerModels) 170 query := db.Model(&partnerModels)
@@ -202,3 +192,40 @@ func (repository PartnerInfoRepository) CountAll(queryOption domain.PartnerFindQ @@ -202,3 +192,40 @@ func (repository PartnerInfoRepository) CountAll(queryOption domain.PartnerFindQ
202 cnt, err := query.Count() 192 cnt, err := query.Count()
203 return cnt, err 193 return cnt, err
204 } 194 }
  195 +
  196 +func (repository *PartnerInfoRepository) transformPgModelToDomainModel(partnerInfoModel *models.PartnerInfo) (domain.PartnerInfo, error) {
  197 + m := domain.PartnerInfo{
  198 + Partner: domain.Partner{
  199 + Id: partnerInfoModel.Id,
  200 + PartnerName: partnerInfoModel.PartnerName,
  201 + Account: partnerInfoModel.Account,
  202 + },
  203 + PartnerCategory: partnerInfoModel.PartnerCategory,
  204 + Password: partnerInfoModel.Password,
  205 + Status: partnerInfoModel.Status,
  206 + CreateAt: partnerInfoModel.CreateAt,
  207 + Salesman: partnerInfoModel.Salesman,
  208 + RegionInfo: partnerInfoModel.RegionInfo,
  209 + CooperateTime: partnerInfoModel.CooperateTime,
  210 + CompanyId: partnerInfoModel.CompanyId,
  211 + Remark: partnerInfoModel.Remark,
  212 + }
  213 + var p []domain.PartnerCategory
  214 + for _, v := range partnerInfoModel.PartnerCategoryInfos {
  215 + category := domain.PartnerCategory{
  216 + Id: v.Id,
  217 + Name: v.Name,
  218 + Code: v.Code,
  219 + }
  220 + p = append(p, category)
  221 + }
  222 + m.PartnerCategoryInfos = p
  223 + return m, nil
  224 +}
  225 +
  226 +func NewPartnerInfoRepository(transactionContext *transaction.TransactionContext) (*PartnerInfoRepository, error) {
  227 + if transactionContext == nil {
  228 + return nil, fmt.Errorf("transactionContext参数不能为nil")
  229 + }
  230 + return &PartnerInfoRepository{transactionContext: transactionContext}, nil
  231 +}
@@ -64,6 +64,7 @@ func (gateway MmmBusinessAdminServiceGateway) httpDo(reqURL string, mathod strin @@ -64,6 +64,7 @@ func (gateway MmmBusinessAdminServiceGateway) httpDo(reqURL string, mathod strin
64 return body, nil 64 return body, nil
65 } 65 }
66 66
  67 +// GetUserAuth 请求企业平台确认用户是否可以使用天联共创后台
67 func (gateway MmmBusinessAdminServiceGateway) GetUserAuth(userId int64) (*ResponseGetUserAuth, error) { 68 func (gateway MmmBusinessAdminServiceGateway) GetUserAuth(userId int64) (*ResponseGetUserAuth, error) {
68 param := map[string]interface{}{ 69 param := map[string]interface{}{
69 "userId": fmt.Sprint(userId), 70 "userId": fmt.Sprint(userId),
@@ -35,14 +35,15 @@ func (c *PartnerInfoController) Prepare() { @@ -35,14 +35,15 @@ func (c *PartnerInfoController) Prepare() {
35 func (c *PartnerInfoController) CreatePartnerInfo() { 35 func (c *PartnerInfoController) CreatePartnerInfo() {
36 //用与适配前端定义的数据结构 36 //用与适配前端定义的数据结构
37 type Parameter struct { 37 type Parameter struct {
38 - PartnerName string `json:"partnerName"`  
39 - PartnerType []int64 `json:"partnerType"`  
40 - Area string `json:"area"`  
41 - Account string `json:"account"`  
42 - State int `json:"state"`  
43 - CooperationTime string `json:"cooperationTime"`  
44 - SalesmanName string `json:"salesmanName"`  
45 - Phone string `json:"phone"` 38 + PartnerName string `json:"partnerName"`
  39 + PartnerType []*domain.PartnerCategory `json:"partnerType"`
  40 + Area string `json:"area"`
  41 + Account string `json:"account"`
  42 + State int `json:"state"`
  43 + CooperationTime string `json:"cooperationTime"`
  44 + SalesmanName string `json:"salesmanName"`
  45 + Phone string `json:"phone"`
  46 + Remark string `json:"remark"`
46 } 47 }
47 var ( 48 var (
48 param Parameter 49 param Parameter
@@ -69,6 +70,7 @@ func (c *PartnerInfoController) CreatePartnerInfo() { @@ -69,6 +70,7 @@ func (c *PartnerInfoController) CreatePartnerInfo() {
69 PartnerCategory: param.PartnerType, 70 PartnerCategory: param.PartnerType,
70 CooperateTime: cooperateTime, 71 CooperateTime: cooperateTime,
71 CompanyId: companyId, 72 CompanyId: companyId,
  73 + Remark: param.Remark,
72 } 74 }
73 if len(param.SalesmanName) > 0 || len(param.Phone) > 0 { 75 if len(param.SalesmanName) > 0 || len(param.Phone) > 0 {
74 cmd.Salesman = []domain.Salesman{ 76 cmd.Salesman = []domain.Salesman{
@@ -103,13 +105,15 @@ func (c *PartnerInfoController) CreatePartnerInfo() { @@ -103,13 +105,15 @@ func (c *PartnerInfoController) CreatePartnerInfo() {
103 func (c *PartnerInfoController) UpdatePartnerInfo() { 105 func (c *PartnerInfoController) UpdatePartnerInfo() {
104 //用与适配前端定义的数据结构 106 //用与适配前端定义的数据结构
105 type Parameter struct { 107 type Parameter struct {
106 - ID int64 `json:"id"`  
107 - PartnerType []int64 `json:"partnerType"`  
108 - Area string `json:"area"`  
109 - State int `json:"state"`  
110 - CooperationTime string `json:"cooperationTime"`  
111 - SalesmanName string `json:"salesmanName"`  
112 - Phone string `json:"phone"` 108 + ID int64 `json:"id"`
  109 + PartnerName string `json:"partnerName"`
  110 + PartnerType []*domain.PartnerCategory `json:"partnerType"`
  111 + Area string `json:"area"`
  112 + State int `json:"state"`
  113 + CooperationTime string `json:"cooperationTime"`
  114 + SalesmanName string `json:"salesmanName"`
  115 + Phone string `json:"phone"`
  116 + Remark string `json:"remark"`
113 } 117 }
114 var ( 118 var (
115 param Parameter 119 param Parameter
@@ -129,6 +133,7 @@ func (c *PartnerInfoController) UpdatePartnerInfo() { @@ -129,6 +133,7 @@ func (c *PartnerInfoController) UpdatePartnerInfo() {
129 companyId := c.GetUserCompany() 133 companyId := c.GetUserCompany()
130 cmd := partnerInfoCmd.UpdatePartnerInfoCommand{ 134 cmd := partnerInfoCmd.UpdatePartnerInfoCommand{
131 Id: param.ID, 135 Id: param.ID,
  136 + PartnerName: param.PartnerName,
132 Status: param.State, 137 Status: param.State,
133 PartnerCategory: param.PartnerType, 138 PartnerCategory: param.PartnerType,
134 CooperateTime: cooperateTime, 139 CooperateTime: cooperateTime,
@@ -142,6 +147,7 @@ func (c *PartnerInfoController) UpdatePartnerInfo() { @@ -142,6 +147,7 @@ func (c *PartnerInfoController) UpdatePartnerInfo() {
142 }, 147 },
143 }, 148 },
144 CompanyId: companyId, 149 CompanyId: companyId,
  150 + Remark: param.Remark,
145 } 151 }
146 serve := partnerInfoService.NewPartnerInfoService(nil) 152 serve := partnerInfoService.NewPartnerInfoService(nil)
147 err = serve.UpdatePartnerInfo(&cmd) 153 err = serve.UpdatePartnerInfo(&cmd)
@@ -190,16 +196,18 @@ func (c *PartnerInfoController) GetPartnerInfo() { @@ -190,16 +196,18 @@ func (c *PartnerInfoController) GetPartnerInfo() {
190 "cooperationTime": partnerInfo.CooperateTime.Local().Format("2006-01-02"), 196 "cooperationTime": partnerInfo.CooperateTime.Local().Format("2006-01-02"),
191 "state": partnerInfo.Status, 197 "state": partnerInfo.Status,
192 "id": partnerInfo.Partner.Id, 198 "id": partnerInfo.Partner.Id,
  199 + "remark": partnerInfo.Remark,
193 } 200 }
194 if len(partnerInfo.Salesman) > 0 { 201 if len(partnerInfo.Salesman) > 0 {
195 rspResult["salesmanName"] = partnerInfo.Salesman[0].Name 202 rspResult["salesmanName"] = partnerInfo.Salesman[0].Name
196 rspResult["phone"] = partnerInfo.Salesman[0].Telephone 203 rspResult["phone"] = partnerInfo.Salesman[0].Telephone
197 } 204 }
198 - partnerTypes := []map[string]interface{}{} 205 + var partnerTypes []map[string]interface{}
199 for _, v := range partnerInfo.PartnerCategoryInfos { 206 for _, v := range partnerInfo.PartnerCategoryInfos {
200 m := map[string]interface{}{ 207 m := map[string]interface{}{
201 "id": v.Id, 208 "id": v.Id,
202 "name": v.Name, 209 "name": v.Name,
  210 + "code": v.Code,
203 } 211 }
204 partnerTypes = append(partnerTypes, m) 212 partnerTypes = append(partnerTypes, m)
205 } 213 }
@@ -208,6 +216,40 @@ func (c *PartnerInfoController) GetPartnerInfo() { @@ -208,6 +216,40 @@ func (c *PartnerInfoController) GetPartnerInfo() {
208 return 216 return
209 } 217 }
210 218
  219 +/**
  220 + * @Author SteveChan
  221 + * @Description // 移除合伙人
  222 + * @Date 15:31 2020/12/29
  223 + * @Param
  224 + * @return
  225 + **/
  226 +func (c *PartnerInfoController) RemovePartnerInfo() {
  227 + //用与适配前端定义的数据结构
  228 + type Parameter struct {
  229 + ID int64 `json:"id"`
  230 + }
  231 + var (
  232 + param Parameter
  233 + err error
  234 + )
  235 + if err = c.BindJsonData(&param); err != nil {
  236 + logs.Error(err)
  237 + c.ResponseError(errors.New("json数据解析失败"))
  238 + return
  239 + }
  240 + cmd := partnerInfoCmd.RemovePartnerInfoCommand{
  241 + Id: param.ID,
  242 + }
  243 + serve := partnerInfoService.NewPartnerInfoService(nil)
  244 + err = serve.RemovePartnerInfo(cmd)
  245 + if err != nil {
  246 + c.ResponseError(err)
  247 + return
  248 + }
  249 + c.ResponseData(nil)
  250 + return
  251 +}
  252 +
211 //PartnerInfoSetState 合伙人批量禁用.启用 253 //PartnerInfoSetState 合伙人批量禁用.启用
212 func (c *PartnerInfoController) PartnerInfoSetState() { 254 func (c *PartnerInfoController) PartnerInfoSetState() {
213 //用与适配前端定义的数据结构 255 //用与适配前端定义的数据结构
@@ -224,19 +266,19 @@ func (c *PartnerInfoController) PartnerInfoSetState() { @@ -224,19 +266,19 @@ func (c *PartnerInfoController) PartnerInfoSetState() {
224 c.ResponseError(errors.New("json数据解析失败")) 266 c.ResponseError(errors.New("json数据解析失败"))
225 return 267 return
226 } 268 }
227 - comanyId := c.GetUserCompany() 269 + companyId := c.GetUserCompany()
228 var cmd partnerInfoCmd.StatusPartnerInfoCommand 270 var cmd partnerInfoCmd.StatusPartnerInfoCommand
229 switch param.Status { 271 switch param.Status {
230 case 0: 272 case 0:
231 cmd = partnerInfoCmd.StatusPartnerInfoCommand{ 273 cmd = partnerInfoCmd.StatusPartnerInfoCommand{
232 Ids: param.Id, 274 Ids: param.Id,
233 - CompanyId: comanyId, 275 + CompanyId: companyId,
234 Status: domain.PARTNER_STATUS_NO, 276 Status: domain.PARTNER_STATUS_NO,
235 } 277 }
236 case 1: 278 case 1:
237 cmd = partnerInfoCmd.StatusPartnerInfoCommand{ 279 cmd = partnerInfoCmd.StatusPartnerInfoCommand{
238 Ids: param.Id, 280 Ids: param.Id,
239 - CompanyId: comanyId, 281 + CompanyId: companyId,
240 Status: domain.PARTNER_STATUS_YES, 282 Status: domain.PARTNER_STATUS_YES,
241 } 283 }
242 default: 284 default:
@@ -256,7 +298,7 @@ func (c *PartnerInfoController) PartnerInfoSetState() { @@ -256,7 +298,7 @@ func (c *PartnerInfoController) PartnerInfoSetState() {
256 //ListPartnerInfo 合伙人列表 298 //ListPartnerInfo 合伙人列表
257 func (c *PartnerInfoController) ListPartnerInfo() { 299 func (c *PartnerInfoController) ListPartnerInfo() {
258 type Parameter struct { 300 type Parameter struct {
259 - Partnertype int `json:"partnerType"` 301 + PartnerType int `json:"partnerType"`
260 Area string `json:"area"` 302 Area string `json:"area"`
261 PartnerName string `json:"partnerName"` 303 PartnerName string `json:"partnerName"`
262 PageSize int `json:"pageSize"` 304 PageSize int `json:"pageSize"`
@@ -280,7 +322,7 @@ func (c *PartnerInfoController) ListPartnerInfo() { @@ -280,7 +322,7 @@ func (c *PartnerInfoController) ListPartnerInfo() {
280 } 322 }
281 companyId := c.GetUserCompany() 323 companyId := c.GetUserCompany()
282 query := partnerQuery.ListPartnerInfoQuery{ 324 query := partnerQuery.ListPartnerInfoQuery{
283 - Partnertype: param.Partnertype, 325 + PartnerType: param.PartnerType,
284 PartnerName: param.PartnerName, 326 PartnerName: param.PartnerName,
285 RegionInfo: param.Area, 327 RegionInfo: param.Area,
286 Limit: param.PageSize, 328 Limit: param.PageSize,
@@ -294,7 +336,7 @@ func (c *PartnerInfoController) ListPartnerInfo() { @@ -294,7 +336,7 @@ func (c *PartnerInfoController) ListPartnerInfo() {
294 c.ResponseError(err) 336 c.ResponseError(err)
295 return 337 return
296 } 338 }
297 - resp := []map[string]interface{}{} 339 + var resp []map[string]interface{}
298 indexBegin := query.Offset 340 indexBegin := query.Offset
299 for i := range partners { 341 for i := range partners {
300 m := map[string]interface{}{ 342 m := map[string]interface{}{
@@ -309,6 +351,7 @@ func (c *PartnerInfoController) ListPartnerInfo() { @@ -309,6 +351,7 @@ func (c *PartnerInfoController) ListPartnerInfo() {
309 "partnerType": partners[i].PartnerCategoryInfos, 351 "partnerType": partners[i].PartnerCategoryInfos,
310 "salesmanName": "", 352 "salesmanName": "",
311 "phone": "", 353 "phone": "",
  354 + "remark": partners[i].Remark,
312 } 355 }
313 if len(partners[i].Salesman) > 0 { 356 if len(partners[i].Salesman) > 0 {
314 m["salesmanName"] = partners[i].Salesman[0].Name 357 m["salesmanName"] = partners[i].Salesman[0].Name
@@ -316,6 +359,9 @@ func (c *PartnerInfoController) ListPartnerInfo() { @@ -316,6 +359,9 @@ func (c *PartnerInfoController) ListPartnerInfo() {
316 } 359 }
317 resp = append(resp, m) 360 resp = append(resp, m)
318 } 361 }
  362 + if len(resp) == 0 {
  363 + resp = []map[string]interface{}{}
  364 + }
319 c.ResponsePageList(resp, count, param.PageNumber) 365 c.ResponsePageList(resp, count, param.PageNumber)
320 return 366 return
321 } 367 }
@@ -32,7 +32,7 @@ func (c *UserController) ListUser() { @@ -32,7 +32,7 @@ func (c *UserController) ListUser() {
32 //用与适配前端定义的数据结构 32 //用与适配前端定义的数据结构
33 type Paramter struct { 33 type Paramter struct {
34 SearchText string `json:"searchText"` 34 SearchText string `json:"searchText"`
35 - PageSize int `json::"pageSize"` 35 + PageSize int `json:"pageSize"`
36 PageNumber int `json:"pageNumber"` 36 PageNumber int `json:"pageNumber"`
37 } 37 }
38 var ( 38 var (
@@ -23,6 +23,7 @@ func init() { @@ -23,6 +23,7 @@ func init() {
23 beego.NSRouter("/edit", &controllers.PartnerInfoController{}, "POST:UpdatePartnerInfo"), 23 beego.NSRouter("/edit", &controllers.PartnerInfoController{}, "POST:UpdatePartnerInfo"),
24 beego.NSRouter("/detail", &controllers.PartnerInfoController{}, "POST:GetPartnerInfo"), 24 beego.NSRouter("/detail", &controllers.PartnerInfoController{}, "POST:GetPartnerInfo"),
25 beego.NSRouter("/batchDisabled", &controllers.PartnerInfoController{}, "POST:PartnerInfoSetState"), 25 beego.NSRouter("/batchDisabled", &controllers.PartnerInfoController{}, "POST:PartnerInfoSetState"),
  26 + beego.NSRouter("/remove", &controllers.PartnerInfoController{}, "POST:RemovePartnerInfo"),
26 ), 27 ),
27 beego.NSNamespace("/dividends", 28 beego.NSNamespace("/dividends",
28 beego.NSRouter("/list", &controllers.OrderDividendController{}, "POST:PageListOrderDividend"), 29 beego.NSRouter("/list", &controllers.OrderDividendController{}, "POST:PageListOrderDividend"),
@@ -8,7 +8,9 @@ import ( @@ -8,7 +8,9 @@ import (
8 //外部调用,企业平台,总后台调用 8 //外部调用,企业平台,总后台调用
9 func init() { 9 func init() {
10 nsPlatform := beego.NewNamespace("/platform", 10 nsPlatform := beego.NewNamespace("/platform",
  11 + //同步企业相关数据
11 beego.NSRouter("/action", &controllers.SyncDataController{}, "post:SyncData"), 12 beego.NSRouter("/action", &controllers.SyncDataController{}, "post:SyncData"),
  13 + //更换公司管理员
12 beego.NSRouter("/admins_change", &controllers.SyncDataController{}, "post:CompanyAdminChance"), 14 beego.NSRouter("/admins_change", &controllers.SyncDataController{}, "post:CompanyAdminChance"),
13 ) 15 )
14 nsUcenter := beego.NewNamespace("/ucenter", 16 nsUcenter := beego.NewNamespace("/ucenter",
@@ -51,6 +51,7 @@ func (c *MessageConsumer) ConsumeClaim(groupSession sarama.ConsumerGroupSession, @@ -51,6 +51,7 @@ func (c *MessageConsumer) ConsumeClaim(groupSession sarama.ConsumerGroupSession,
51 } 51 }
52 if err = topicHandle(message); err != nil { 52 if err = topicHandle(message); err != nil {
53 logs.Error("Message claimed: kafka消息处理错误 topic =", message.Topic, message.Offset, err) 53 logs.Error("Message claimed: kafka消息处理错误 topic =", message.Topic, message.Offset, err)
  54 +
54 } 55 }
55 groupSession.MarkMessage(message, "") 56 groupSession.MarkMessage(message, "")
56 } 57 }
@@ -30,6 +30,9 @@ func init() { @@ -30,6 +30,9 @@ func init() {
30 if runEnv == "partnermg_prd" { 30 if runEnv == "partnermg_prd" {
31 initHandleRoutersProd() 31 initHandleRoutersProd()
32 } 32 }
  33 + if runEnv == "partnermg_dev" {
  34 + initHandleRoutersDev()
  35 + }
33 } 36 }
34 37
35 func initHandleRoutersTest() { 38 func initHandleRoutersTest() {
@@ -39,3 +42,7 @@ func initHandleRoutersTest() { @@ -39,3 +42,7 @@ func initHandleRoutersTest() {
39 func initHandleRoutersProd() { 42 func initHandleRoutersProd() {
40 TopicHandleRouters["xiangmi_project"] = handles.DataFromXiangMi 43 TopicHandleRouters["xiangmi_project"] = handles.DataFromXiangMi
41 } 44 }
  45 +
  46 +func initHandleRoutersDev() {
  47 + TopicHandleRouters["xiangmi_project_dev"] = handles.DataFromXiangMi
  48 +}
此 diff 太大无法显示。
1 -package geetest  
2 -  
3 -import (  
4 - "crypto/md5"  
5 - "encoding/hex"  
6 - "encoding/json"  
7 - "errors"  
8 - "io/ioutil"  
9 - "net/http"  
10 - "net/url"  
11 - "strings"  
12 - "time"  
13 -)  
14 -  
15 -type GeetestLib struct {  
16 - CaptchaID string  
17 - PrivateKey string  
18 - Client *http.Client  
19 -}  
20 -  
21 -type FailbackRegisterRespnse struct {  
22 - Success int `json:"success"`  
23 - GT string `json:"gt"`  
24 - Challenge string `json:"challenge"`  
25 - NewCaptcha int `json:"new_captcha"`  
26 -}  
27 -  
28 -const (  
29 - geetestHost = "http://api.geetest.com"  
30 - registerURL = geetestHost + "/register.php"  
31 - validateURL = geetestHost + "/validate.php"  
32 -)  
33 -  
34 -func MD5Encode(input string) string {  
35 - md5Instant := md5.New()  
36 - md5Instant.Write([]byte(input))  
37 - return hex.EncodeToString(md5Instant.Sum(nil))  
38 -}  
39 -  
40 -// 初始化 GeetestLib  
41 -func NewGeetestLib(capthcaID string, privateKey string, timeOut time.Duration) (geetest GeetestLib){  
42 - client := &http.Client{Timeout: timeOut}  
43 - geetest = GeetestLib{capthcaID, privateKey, client}  
44 - return  
45 -}  
46 -  
47 -func (g *GeetestLib) getFailBackRegisterResponse(success int, challenge string) []byte {  
48 - if challenge == "" {  
49 - challenge = hex.EncodeToString(md5.New().Sum(nil))  
50 - }  
51 -  
52 - response := FailbackRegisterRespnse{  
53 - success,  
54 - g.CaptchaID,  
55 - challenge,  
56 - 1,  
57 - }  
58 - res, _ := json.Marshal(response)  
59 - return res  
60 -}  
61 -  
62 -func (g *GeetestLib) do(req *http.Request) (body []byte, err error) {  
63 - req.Header.Set("Content-Type", "application/x-www-form-urlencoded")  
64 - var resp *http.Response  
65 - if resp, err = g.Client.Do(req); err != nil {  
66 - return  
67 - }  
68 - defer resp.Body.Close()  
69 - if resp.StatusCode >= http.StatusInternalServerError {  
70 - err = errors.New("http status code 5xx")  
71 - return  
72 - }  
73 -  
74 - if body, err = ioutil.ReadAll(resp.Body); err != nil {  
75 - return  
76 - }  
77 - return  
78 -}  
79 -  
80 -func (g *GeetestLib) PreProcess(userID string, userIP string) (int8, []byte) {  
81 - params := url.Values{}  
82 - params.Add("gt", g.CaptchaID)  
83 - params.Add("new_captcha", "1")  
84 - if userID != "" {  
85 - params.Add("user_id", userID)  
86 - }  
87 - if userIP != "" {  
88 - params.Add("ip_adress", userIP)  
89 - }  
90 - req, _ := http.NewRequest("GET", registerURL+"?"+params.Encode(), nil)  
91 - body, err := g.do(req)  
92 - if err != nil {  
93 - return 0, g.getFailBackRegisterResponse(0, "")  
94 - }  
95 - challenge := string(body)  
96 - if len(challenge) != 32 {  
97 - return 0, g.getFailBackRegisterResponse(0, "")  
98 - } else {  
99 - challenge = MD5Encode(challenge + g.PrivateKey)  
100 - return 1, g.getFailBackRegisterResponse(1, challenge)  
101 - }  
102 -}  
103 -  
104 -func (g *GeetestLib) checkParas(challenge string, validate string, seccode string) bool {  
105 - if challenge == "" || validate == "" || seccode == "" {  
106 - return false  
107 - }  
108 - return true  
109 -}  
110 -  
111 -func (g *GeetestLib) checkSuccessRes(challenge string, validate string) bool {  
112 - return MD5Encode(g.PrivateKey+"geetest"+challenge) == validate  
113 -}  
114 -  
115 -func (g *GeetestLib) checkFailbackRes(challenge string, validate string) bool {  
116 - return MD5Encode(challenge) == validate  
117 -}  
118 -  
119 -func (g *GeetestLib) SuccessValidate(challenge string, validate string, seccode string, userID string, userIP string) bool {  
120 - if !g.checkParas(challenge, validate, seccode) {  
121 - return false  
122 - }  
123 - if !g.checkSuccessRes(challenge, validate) {  
124 - return false  
125 - }  
126 - params := url.Values{}  
127 - params.Add("seccode", seccode)  
128 - params.Add("challenge", challenge)  
129 - params.Add("captchaid", g.CaptchaID)  
130 - params.Add("sdk", "golang_v1.0.0")  
131 - if userID != "" {  
132 - params.Add("user_id", userID)  
133 - }  
134 - if userIP != "" {  
135 - params.Add("ip_adress", userIP)  
136 - }  
137 - req, _ := http.NewRequest("POST", validateURL, strings.NewReader(params.Encode()))  
138 - body, err := g.do(req)  
139 - if err != nil {  
140 - return false  
141 - }  
142 - res := string(body)  
143 - return res == MD5Encode(seccode)  
144 -}  
145 -  
146 -func (g *GeetestLib) FailbackValidate(challenge string, validate string, seccode string) bool {  
147 - if !g.checkParas(challenge, validate, seccode) {  
148 - return false  
149 - }  
150 - if !g.checkFailbackRes(challenge, validate) {  
151 - return false  
152 - }  
153 - return true  
154 -}  
1 -language: go  
2 -go:  
3 - - 1.2  
4 - - stable 1 +language: go
  2 +go:
  3 + - 1.2
  4 + - stable
5 - tip 5 - tip
1 -A reader for Microsoft's Compound File Binary File Format.  
2 -  
3 -Example usage:  
4 -  
5 - file, _ := os.Open("test/test.doc")  
6 - defer file.Close()  
7 - doc, err := mscfb.New(file)  
8 - if err != nil {  
9 - log.Fatal(err)  
10 - }  
11 - for entry, err := doc.Next(); err == nil; entry, err = doc.Next() {  
12 - buf := make([]byte, 512)  
13 - i, _ := doc.Read(buf)  
14 - if i > 0 {  
15 - fmt.Println(buf[:i])  
16 - }  
17 - fmt.Println(entry.Name)  
18 - }  
19 -  
20 -The Compound File Binary File Format is also known as the Object Linking and Embedding (OLE) or Component Object Model (COM) format and was used by early MS software such as MS Office. See [http://msdn.microsoft.com/en-us/library/dd942138.aspx](http://msdn.microsoft.com/en-us/library/dd942138.aspx) for more details  
21 -  
22 -Install with `go get github.com/richardlehane/mscfb`  
23 - 1 +A reader for Microsoft's Compound File Binary File Format.
  2 +
  3 +Example usage:
  4 +
  5 + file, _ := os.Open("test/test.doc")
  6 + defer file.Close()
  7 + doc, err := mscfb.New(file)
  8 + if err != nil {
  9 + log.Fatal(err)
  10 + }
  11 + for entry, err := doc.Next(); err == nil; entry, err = doc.Next() {
  12 + buf := make([]byte, 512)
  13 + i, _ := doc.Read(buf)
  14 + if i > 0 {
  15 + fmt.Println(buf[:i])
  16 + }
  17 + fmt.Println(entry.Name)
  18 + }
  19 +
  20 +The Compound File Binary File Format is also known as the Object Linking and Embedding (OLE) or Component Object Model (COM) format and was used by early MS software such as MS Office. See [http://msdn.microsoft.com/en-us/library/dd942138.aspx](http://msdn.microsoft.com/en-us/library/dd942138.aspx) for more details
  21 +
  22 +Install with `go get github.com/richardlehane/mscfb`
  23 +
24 [![Build Status](https://travis-ci.org/richardlehane/mscfb.png?branch=master)](https://travis-ci.org/richardlehane/mscfb) 24 [![Build Status](https://travis-ci.org/richardlehane/mscfb.png?branch=master)](https://travis-ci.org/richardlehane/mscfb)
1 -// +build gofuzz  
2 -  
3 -// fuzzing with https://github.com/dvyukov/go-fuzz  
4 -package mscfb  
5 -  
6 -import (  
7 - "bytes"  
8 - "io"  
9 -)  
10 -  
11 -func Fuzz(data []byte) int {  
12 - doc, err := New(bytes.NewReader(data))  
13 - if err != nil {  
14 - if doc != nil {  
15 - panic("doc != nil on error " + err.Error())  
16 - }  
17 - return 0  
18 - }  
19 - buf := &bytes.Buffer{}  
20 - for entry, err := doc.Next(); ; entry, err = doc.Next() {  
21 - if err != nil {  
22 - if err == io.EOF {  
23 - return 1  
24 - }  
25 - if entry != nil {  
26 - panic("entry != nil on error " + err.Error())  
27 - }  
28 - }  
29 - buf.Reset()  
30 - buf.ReadFrom(entry)  
31 - }  
32 - return 1  
33 -} 1 +// +build gofuzz
  2 +
  3 +// fuzzing with https://github.com/dvyukov/go-fuzz
  4 +package mscfb
  5 +
  6 +import (
  7 + "bytes"
  8 + "io"
  9 +)
  10 +
  11 +func Fuzz(data []byte) int {
  12 + doc, err := New(bytes.NewReader(data))
  13 + if err != nil {
  14 + if doc != nil {
  15 + panic("doc != nil on error " + err.Error())
  16 + }
  17 + return 0
  18 + }
  19 + buf := &bytes.Buffer{}
  20 + for entry, err := doc.Next(); ; entry, err = doc.Next() {
  21 + if err != nil {
  22 + if err == io.EOF {
  23 + return 1
  24 + }
  25 + if entry != nil {
  26 + panic("entry != nil on error " + err.Error())
  27 + }
  28 + }
  29 + buf.Reset()
  30 + buf.ReadFrom(entry)
  31 + }
  32 + return 1
  33 +}
1 -// Copyright 2013 Richard Lehane. All rights reserved.  
2 -//  
3 -// Licensed under the Apache License, Version 2.0 (the "License");  
4 -// you may not use this file except in compliance with the License.  
5 -// You may obtain a copy of the License at  
6 -//  
7 -// http://www.apache.org/licenses/LICENSE-2.0  
8 -//  
9 -// Unless required by applicable law or agreed to in writing, software  
10 -// distributed under the License is distributed on an "AS IS" BASIS,  
11 -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  
12 -// See the License for the specific language governing permissions and  
13 -// limitations under the License.  
14 -  
15 -// Package mscfb implements a reader for Microsoft's Compound File Binary File Format (http://msdn.microsoft.com/en-us/library/dd942138.aspx).  
16 -//  
17 -// The Compound File Binary File Format is also known as the Object Linking and Embedding (OLE) or Component Object Model (COM) format and was used by many  
18 -// early MS software such as MS Office.  
19 -//  
20 -// Example:  
21 -// file, _ := os.Open("test/test.doc")  
22 -// defer file.Close()  
23 -// doc, err := mscfb.New(file)  
24 -// if err != nil {  
25 -// log.Fatal(err)  
26 -// }  
27 -// for entry, err := doc.Next(); err == nil; entry, err = doc.Next() {  
28 -// buf := make([]byte, 512)  
29 -// i, _ := entry.Read(buf)  
30 -// if i > 0 {  
31 -// fmt.Println(buf[:i])  
32 -// }  
33 -// fmt.Println(entry.Name)  
34 -// }  
35 -package mscfb  
36 -  
37 -import (  
38 - "encoding/binary"  
39 - "io"  
40 - "strconv"  
41 - "time"  
42 -)  
43 -  
44 -func fileOffset(ss, sn uint32) int64 {  
45 - return int64((sn + 1) * ss)  
46 -}  
47 -  
48 -const (  
49 - signature uint64 = 0xE11AB1A1E011CFD0  
50 - miniStreamSectorSize uint32 = 64  
51 - miniStreamCutoffSize int64 = 4096  
52 - dirEntrySize uint32 = 128 //128 bytes  
53 -)  
54 -  
55 -const (  
56 - maxRegSect uint32 = 0xFFFFFFFA // Maximum regular sector number  
57 - difatSect uint32 = 0xFFFFFFFC //Specifies a DIFAT sector in the FAT  
58 - fatSect uint32 = 0xFFFFFFFD // Specifies a FAT sector in the FAT  
59 - endOfChain uint32 = 0xFFFFFFFE // End of linked chain of sectors  
60 - freeSect uint32 = 0xFFFFFFFF // Speficies unallocated sector in the FAT, Mini FAT or DIFAT  
61 - maxRegStreamID uint32 = 0xFFFFFFFA // maximum regular stream ID  
62 - noStream uint32 = 0xFFFFFFFF // empty pointer  
63 -)  
64 -  
65 -const lenHeader int = 8 + 16 + 10 + 6 + 12 + 8 + 16 + 109*4  
66 -  
67 -type headerFields struct {  
68 - signature uint64  
69 - _ [16]byte //CLSID - ignore, must be null  
70 - minorVersion uint16 //Version number for non-breaking changes. This field SHOULD be set to 0x003E if the major version field is either 0x0003 or 0x0004.  
71 - majorVersion uint16 //Version number for breaking changes. This field MUST be set to either 0x0003 (version 3) or 0x0004 (version 4).  
72 - _ [2]byte //byte order - ignore, must be little endian  
73 - sectorSize uint16 //This field MUST be set to 0x0009, or 0x000c, depending on the Major Version field. This field specifies the sector size of the compound file as a power of 2. If Major Version is 3, then the Sector Shift MUST be 0x0009, specifying a sector size of 512 bytes. If Major Version is 4, then the Sector Shift MUST be 0x000C, specifying a sector size of 4096 bytes.  
74 - _ [2]byte // ministream sector size - ignore, must be 64 bytes  
75 - _ [6]byte // reserved - ignore, not used  
76 - numDirectorySectors uint32 //This integer field contains the count of the number of directory sectors in the compound file. If Major Version is 3, then the Number of Directory Sectors MUST be zero. This field is not supported for version 3 compound files.  
77 - numFatSectors uint32 //This integer field contains the count of the number of FAT sectors in the compound file.  
78 - directorySectorLoc uint32 //This integer field contains the starting sector number for the directory stream.  
79 - _ [4]byte // transaction - ignore, not used  
80 - _ [4]byte // mini stream size cutooff - ignore, must be 4096 bytes  
81 - miniFatSectorLoc uint32 //This integer field contains the starting sector number for the mini FAT.  
82 - numMiniFatSectors uint32 //This integer field contains the count of the number of mini FAT sectors in the compound file.  
83 - difatSectorLoc uint32 //This integer field contains the starting sector number for the DIFAT.  
84 - numDifatSectors uint32 //This integer field contains the count of the number of DIFAT sectors in the compound file.  
85 - initialDifats [109]uint32 //The first 109 difat sectors are included in the header  
86 -}  
87 -  
88 -func makeHeader(b []byte) *headerFields {  
89 - h := &headerFields{}  
90 - h.signature = binary.LittleEndian.Uint64(b[:8])  
91 - h.minorVersion = binary.LittleEndian.Uint16(b[24:26])  
92 - h.majorVersion = binary.LittleEndian.Uint16(b[26:28])  
93 - h.sectorSize = binary.LittleEndian.Uint16(b[30:32])  
94 - h.numDirectorySectors = binary.LittleEndian.Uint32(b[40:44])  
95 - h.numFatSectors = binary.LittleEndian.Uint32(b[44:48])  
96 - h.directorySectorLoc = binary.LittleEndian.Uint32(b[48:52])  
97 - h.miniFatSectorLoc = binary.LittleEndian.Uint32(b[60:64])  
98 - h.numMiniFatSectors = binary.LittleEndian.Uint32(b[64:68])  
99 - h.difatSectorLoc = binary.LittleEndian.Uint32(b[68:72])  
100 - h.numDifatSectors = binary.LittleEndian.Uint32(b[72:76])  
101 - var idx int  
102 - for i := 76; i < 512; i = i + 4 {  
103 - h.initialDifats[idx] = binary.LittleEndian.Uint32(b[i : i+4])  
104 - idx++  
105 - }  
106 - return h  
107 -}  
108 -  
109 -type header struct {  
110 - *headerFields  
111 - difats []uint32  
112 - miniFatLocs []uint32  
113 - miniStreamLocs []uint32 // chain of sectors containing the ministream  
114 -}  
115 -  
116 -func (r *Reader) setHeader() error {  
117 - buf, err := r.readAt(0, lenHeader)  
118 - if err != nil {  
119 - return err  
120 - }  
121 - r.header = &header{headerFields: makeHeader(buf)}  
122 - // sanity check - check signature  
123 - if r.header.signature != signature {  
124 - return Error{ErrFormat, "bad signature", int64(r.header.signature)}  
125 - }  
126 - // check for legal sector size  
127 - if r.header.sectorSize == 0x0009 || r.header.sectorSize == 0x000c {  
128 - r.sectorSize = uint32(1 << r.header.sectorSize)  
129 - } else {  
130 - return Error{ErrFormat, "illegal sector size", int64(r.header.sectorSize)}  
131 - }  
132 - // check for DIFAT overflow  
133 - if r.header.numDifatSectors > 0 {  
134 - sz := (r.sectorSize / 4) - 1  
135 - if int(r.header.numDifatSectors*sz+109) < 0 {  
136 - return Error{ErrFormat, "DIFAT int overflow", int64(r.header.numDifatSectors)}  
137 - }  
138 - if r.header.numDifatSectors*sz+109 > r.header.numFatSectors+sz {  
139 - return Error{ErrFormat, "num DIFATs exceeds FAT sectors", int64(r.header.numDifatSectors)}  
140 - }  
141 - }  
142 - // check for mini FAT overflow  
143 - if r.header.numMiniFatSectors > 0 {  
144 - if int(r.sectorSize/4*r.header.numMiniFatSectors) < 0 {  
145 - return Error{ErrFormat, "mini FAT int overflow", int64(r.header.numMiniFatSectors)}  
146 - }  
147 - if r.header.numMiniFatSectors > r.header.numFatSectors*(r.sectorSize/miniStreamSectorSize) {  
148 - return Error{ErrFormat, "num mini FATs exceeds FAT sectors", int64(r.header.numFatSectors)}  
149 - }  
150 - }  
151 - return nil  
152 -}  
153 -  
154 -func (r *Reader) setDifats() error {  
155 - r.header.difats = r.header.initialDifats[:]  
156 - // return early if no extra DIFAT sectors  
157 - if r.header.numDifatSectors == 0 {  
158 - return nil  
159 - }  
160 - sz := (r.sectorSize / 4) - 1  
161 - n := make([]uint32, 109, r.header.numDifatSectors*sz+109)  
162 - copy(n, r.header.difats)  
163 - r.header.difats = n  
164 - off := r.header.difatSectorLoc  
165 - for i := 0; i < int(r.header.numDifatSectors); i++ {  
166 - buf, err := r.readAt(fileOffset(r.sectorSize, off), int(r.sectorSize))  
167 - if err != nil {  
168 - return Error{ErrFormat, "error setting DIFAT(" + err.Error() + ")", int64(off)}  
169 - }  
170 - for j := 0; j < int(sz); j++ {  
171 - r.header.difats = append(r.header.difats, binary.LittleEndian.Uint32(buf[j*4:j*4+4]))  
172 - }  
173 - off = binary.LittleEndian.Uint32(buf[len(buf)-4:])  
174 - }  
175 - return nil  
176 -}  
177 -  
178 -// set the ministream FAT and sector slices in the header  
179 -func (r *Reader) setMiniStream() error {  
180 - // do nothing if there is no ministream  
181 - if r.direntries[0].startingSectorLoc == endOfChain || r.header.miniFatSectorLoc == endOfChain || r.header.numMiniFatSectors == 0 {  
182 - return nil  
183 - }  
184 - // build a slice of minifat sectors (akin to the DIFAT slice)  
185 - c := int(r.header.numMiniFatSectors)  
186 - r.header.miniFatLocs = make([]uint32, c)  
187 - r.header.miniFatLocs[0] = r.header.miniFatSectorLoc  
188 - for i := 1; i < c; i++ {  
189 - loc, err := r.findNext(r.header.miniFatLocs[i-1], false)  
190 - if err != nil {  
191 - return Error{ErrFormat, "setting mini stream (" + err.Error() + ")", int64(r.header.miniFatLocs[i-1])}  
192 - }  
193 - r.header.miniFatLocs[i] = loc  
194 - }  
195 - // build a slice of ministream sectors  
196 - c = int(r.sectorSize / 4 * r.header.numMiniFatSectors)  
197 - r.header.miniStreamLocs = make([]uint32, 0, c)  
198 - sn := r.direntries[0].startingSectorLoc  
199 - var err error  
200 - for sn != endOfChain {  
201 - r.header.miniStreamLocs = append(r.header.miniStreamLocs, sn)  
202 - sn, err = r.findNext(sn, false)  
203 - if err != nil {  
204 - return Error{ErrFormat, "setting mini stream (" + err.Error() + ")", int64(sn)}  
205 - }  
206 - }  
207 - return nil  
208 -}  
209 -  
210 -func (r *Reader) readAt(offset int64, length int) ([]byte, error) {  
211 - if r.slicer {  
212 - b, err := r.ra.(slicer).Slice(offset, length)  
213 - if err != nil {  
214 - return nil, Error{ErrRead, "slicer read error (" + err.Error() + ")", offset}  
215 - }  
216 - return b, nil  
217 - }  
218 - if length > len(r.buf) {  
219 - return nil, Error{ErrRead, "read length greater than read buffer", int64(length)}  
220 - }  
221 - if _, err := r.ra.ReadAt(r.buf[:length], offset); err != nil {  
222 - return nil, Error{ErrRead, err.Error(), offset}  
223 - }  
224 - return r.buf[:length], nil  
225 -}  
226 -  
227 -func (r *Reader) getOffset(sn uint32, mini bool) (int64, error) {  
228 - if mini {  
229 - num := r.sectorSize / 64  
230 - sec := int(sn / num)  
231 - if sec >= len(r.header.miniStreamLocs) {  
232 - return 0, Error{ErrRead, "minisector number is outside minisector range", int64(sec)}  
233 - }  
234 - dif := sn % num  
235 - return int64((r.header.miniStreamLocs[sec]+1)*r.sectorSize + dif*64), nil  
236 - }  
237 - return fileOffset(r.sectorSize, sn), nil  
238 -}  
239 -  
240 -// check the FAT sector for the next sector in a chain  
241 -func (r *Reader) findNext(sn uint32, mini bool) (uint32, error) {  
242 - entries := r.sectorSize / 4  
243 - index := int(sn / entries) // find position in DIFAT or minifat array  
244 - var sect uint32  
245 - if mini {  
246 - if index < 0 || index >= len(r.header.miniFatLocs) {  
247 - return 0, Error{ErrRead, "minisector index is outside miniFAT range", int64(index)}  
248 - }  
249 - sect = r.header.miniFatLocs[index]  
250 - } else {  
251 - if index < 0 || index >= len(r.header.difats) {  
252 - return 0, Error{ErrRead, "FAT index is outside DIFAT range", int64(index)}  
253 - }  
254 - sect = r.header.difats[index]  
255 - }  
256 - fatIndex := sn % entries // find position within FAT or MiniFAT sector  
257 - offset := fileOffset(r.sectorSize, sect) + int64(fatIndex*4)  
258 - buf, err := r.readAt(offset, 4)  
259 - if err != nil {  
260 - return 0, Error{ErrRead, "bad read finding next sector (" + err.Error() + ")", offset}  
261 - }  
262 - return binary.LittleEndian.Uint32(buf), nil  
263 -}  
264 -  
265 -// Reader provides sequential access to the contents of a MS compound file (MSCFB)  
266 -type Reader struct {  
267 - slicer bool  
268 - sectorSize uint32  
269 - buf []byte  
270 - header *header  
271 - File []*File // File is an ordered slice of final directory entries.  
272 - direntries []*File // unordered raw directory entries  
273 - entry int  
274 -  
275 - ra io.ReaderAt  
276 - wa io.WriterAt  
277 -}  
278 -  
279 -// New returns a MSCFB reader  
280 -func New(ra io.ReaderAt) (*Reader, error) {  
281 - r := &Reader{ra: ra}  
282 - if _, ok := ra.(slicer); ok {  
283 - r.slicer = true  
284 - } else {  
285 - r.buf = make([]byte, lenHeader)  
286 - }  
287 - if err := r.setHeader(); err != nil {  
288 - return nil, err  
289 - }  
290 - // resize the buffer to 4096 if sector size isn't 512  
291 - if !r.slicer && int(r.sectorSize) > len(r.buf) {  
292 - r.buf = make([]byte, r.sectorSize)  
293 - }  
294 - if err := r.setDifats(); err != nil {  
295 - return nil, err  
296 - }  
297 - if err := r.setDirEntries(); err != nil {  
298 - return nil, err  
299 - }  
300 - if err := r.setMiniStream(); err != nil {  
301 - return nil, err  
302 - }  
303 - if err := r.traverse(); err != nil {  
304 - return nil, err  
305 - }  
306 - return r, nil  
307 -}  
308 -  
309 -// ID returns the CLSID (class ID) field from the root directory entry  
310 -func (r *Reader) ID() string {  
311 - return r.File[0].ID()  
312 -}  
313 -  
314 -// Created returns the created field from the root directory entry  
315 -func (r *Reader) Created() time.Time {  
316 - return r.File[0].Created()  
317 -}  
318 -  
319 -// Modified returns the last modified field from the root directory entry  
320 -func (r *Reader) Modified() time.Time {  
321 - return r.File[0].Modified()  
322 -}  
323 -  
324 -// Next iterates to the next directory entry.  
325 -// This isn't necessarily an adjacent *File within the File slice, but is based on the Left Sibling, Right Sibling and Child information in directory entries.  
326 -func (r *Reader) Next() (*File, error) {  
327 - r.entry++  
328 - if r.entry >= len(r.File) {  
329 - return nil, io.EOF  
330 - }  
331 - return r.File[r.entry], nil  
332 -}  
333 -  
334 -// Read the current directory entry  
335 -func (r *Reader) Read(b []byte) (n int, err error) {  
336 - if r.entry >= len(r.File) {  
337 - return 0, io.EOF  
338 - }  
339 - return r.File[r.entry].Read(b)  
340 -}  
341 -  
342 -// Debug provides granular information from an mscfb file to assist with debugging  
343 -func (r *Reader) Debug() map[string][]uint32 {  
344 - ret := map[string][]uint32{  
345 - "sector size": []uint32{r.sectorSize},  
346 - "mini fat locs": r.header.miniFatLocs,  
347 - "mini stream locs": r.header.miniStreamLocs,  
348 - "directory sector": []uint32{r.header.directorySectorLoc},  
349 - "mini stream start/size": []uint32{r.File[0].startingSectorLoc, binary.LittleEndian.Uint32(r.File[0].streamSize[:])},  
350 - }  
351 - for f, err := r.Next(); err == nil; f, err = r.Next() {  
352 - ret[f.Name+" start/size"] = []uint32{f.startingSectorLoc, binary.LittleEndian.Uint32(f.streamSize[:])}  
353 - }  
354 - return ret  
355 -}  
356 -  
357 -const (  
358 - // ErrFormat reports issues with the MSCFB's header structures  
359 - ErrFormat = iota  
360 - // ErrRead reports issues attempting to read MSCFB streams  
361 - ErrRead  
362 - // ErrSeek reports seek issues  
363 - ErrSeek  
364 - // ErrWrite reports write issues  
365 - ErrWrite  
366 - // ErrTraverse reports issues attempting to traverse the child-parent-sibling relations  
367 - // between MSCFB storage objects  
368 - ErrTraverse  
369 -)  
370 -  
371 -type Error struct {  
372 - typ int  
373 - msg string  
374 - val int64  
375 -}  
376 -  
377 -func (e Error) Error() string {  
378 - return "mscfb: " + e.msg + "; " + strconv.FormatInt(e.val, 10)  
379 -}  
380 -  
381 -// Typ gives the type of MSCFB error  
382 -func (e Error) Typ() int {  
383 - return e.typ  
384 -}  
385 -  
386 -// Slicer interface avoids a copy by obtaining a byte slice directly from the underlying reader  
387 -type slicer interface {  
388 - Slice(offset int64, length int) ([]byte, error)  
389 -} 1 +// Copyright 2013 Richard Lehane. All rights reserved.
  2 +//
  3 +// Licensed under the Apache License, Version 2.0 (the "License");
  4 +// you may not use this file except in compliance with the License.
  5 +// You may obtain a copy of the License at
  6 +//
  7 +// http://www.apache.org/licenses/LICENSE-2.0
  8 +//
  9 +// Unless required by applicable law or agreed to in writing, software
  10 +// distributed under the License is distributed on an "AS IS" BASIS,
  11 +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12 +// See the License for the specific language governing permissions and
  13 +// limitations under the License.
  14 +
  15 +// Package mscfb implements a reader for Microsoft's Compound File Binary File Format (http://msdn.microsoft.com/en-us/library/dd942138.aspx).
  16 +//
  17 +// The Compound File Binary File Format is also known as the Object Linking and Embedding (OLE) or Component Object Model (COM) format and was used by many
  18 +// early MS software such as MS Office.
  19 +//
  20 +// Example:
  21 +// file, _ := os.Open("test/test.doc")
  22 +// defer file.Close()
  23 +// doc, err := mscfb.New(file)
  24 +// if err != nil {
  25 +// log.Fatal(err)
  26 +// }
  27 +// for entry, err := doc.Next(); err == nil; entry, err = doc.Next() {
  28 +// buf := make([]byte, 512)
  29 +// i, _ := entry.Read(buf)
  30 +// if i > 0 {
  31 +// fmt.Println(buf[:i])
  32 +// }
  33 +// fmt.Println(entry.Name)
  34 +// }
  35 +package mscfb
  36 +
  37 +import (
  38 + "encoding/binary"
  39 + "io"
  40 + "strconv"
  41 + "time"
  42 +)
  43 +
  44 +func fileOffset(ss, sn uint32) int64 {
  45 + return int64((sn + 1) * ss)
  46 +}
  47 +
  48 +const (
  49 + signature uint64 = 0xE11AB1A1E011CFD0
  50 + miniStreamSectorSize uint32 = 64
  51 + miniStreamCutoffSize int64 = 4096
  52 + dirEntrySize uint32 = 128 //128 bytes
  53 +)
  54 +
  55 +const (
  56 + maxRegSect uint32 = 0xFFFFFFFA // Maximum regular sector number
  57 + difatSect uint32 = 0xFFFFFFFC //Specifies a DIFAT sector in the FAT
  58 + fatSect uint32 = 0xFFFFFFFD // Specifies a FAT sector in the FAT
  59 + endOfChain uint32 = 0xFFFFFFFE // End of linked chain of sectors
  60 + freeSect uint32 = 0xFFFFFFFF // Speficies unallocated sector in the FAT, Mini FAT or DIFAT
  61 + maxRegStreamID uint32 = 0xFFFFFFFA // maximum regular stream ID
  62 + noStream uint32 = 0xFFFFFFFF // empty pointer
  63 +)
  64 +
  65 +const lenHeader int = 8 + 16 + 10 + 6 + 12 + 8 + 16 + 109*4
  66 +
  67 +type headerFields struct {
  68 + signature uint64
  69 + _ [16]byte //CLSID - ignore, must be null
  70 + minorVersion uint16 //Version number for non-breaking changes. This field SHOULD be set to 0x003E if the major version field is either 0x0003 or 0x0004.
  71 + majorVersion uint16 //Version number for breaking changes. This field MUST be set to either 0x0003 (version 3) or 0x0004 (version 4).
  72 + _ [2]byte //byte order - ignore, must be little endian
  73 + sectorSize uint16 //This field MUST be set to 0x0009, or 0x000c, depending on the Major Version field. This field specifies the sector size of the compound file as a power of 2. If Major Version is 3, then the Sector Shift MUST be 0x0009, specifying a sector size of 512 bytes. If Major Version is 4, then the Sector Shift MUST be 0x000C, specifying a sector size of 4096 bytes.
  74 + _ [2]byte // ministream sector size - ignore, must be 64 bytes
  75 + _ [6]byte // reserved - ignore, not used
  76 + numDirectorySectors uint32 //This integer field contains the count of the number of directory sectors in the compound file. If Major Version is 3, then the Number of Directory Sectors MUST be zero. This field is not supported for version 3 compound files.
  77 + numFatSectors uint32 //This integer field contains the count of the number of FAT sectors in the compound file.
  78 + directorySectorLoc uint32 //This integer field contains the starting sector number for the directory stream.
  79 + _ [4]byte // transaction - ignore, not used
  80 + _ [4]byte // mini stream size cutooff - ignore, must be 4096 bytes
  81 + miniFatSectorLoc uint32 //This integer field contains the starting sector number for the mini FAT.
  82 + numMiniFatSectors uint32 //This integer field contains the count of the number of mini FAT sectors in the compound file.
  83 + difatSectorLoc uint32 //This integer field contains the starting sector number for the DIFAT.
  84 + numDifatSectors uint32 //This integer field contains the count of the number of DIFAT sectors in the compound file.
  85 + initialDifats [109]uint32 //The first 109 difat sectors are included in the header
  86 +}
  87 +
  88 +func makeHeader(b []byte) *headerFields {
  89 + h := &headerFields{}
  90 + h.signature = binary.LittleEndian.Uint64(b[:8])
  91 + h.minorVersion = binary.LittleEndian.Uint16(b[24:26])
  92 + h.majorVersion = binary.LittleEndian.Uint16(b[26:28])
  93 + h.sectorSize = binary.LittleEndian.Uint16(b[30:32])
  94 + h.numDirectorySectors = binary.LittleEndian.Uint32(b[40:44])
  95 + h.numFatSectors = binary.LittleEndian.Uint32(b[44:48])
  96 + h.directorySectorLoc = binary.LittleEndian.Uint32(b[48:52])
  97 + h.miniFatSectorLoc = binary.LittleEndian.Uint32(b[60:64])
  98 + h.numMiniFatSectors = binary.LittleEndian.Uint32(b[64:68])
  99 + h.difatSectorLoc = binary.LittleEndian.Uint32(b[68:72])
  100 + h.numDifatSectors = binary.LittleEndian.Uint32(b[72:76])
  101 + var idx int
  102 + for i := 76; i < 512; i = i + 4 {
  103 + h.initialDifats[idx] = binary.LittleEndian.Uint32(b[i : i+4])
  104 + idx++
  105 + }
  106 + return h
  107 +}
  108 +
  109 +type header struct {
  110 + *headerFields
  111 + difats []uint32
  112 + miniFatLocs []uint32
  113 + miniStreamLocs []uint32 // chain of sectors containing the ministream
  114 +}
  115 +
  116 +func (r *Reader) setHeader() error {
  117 + buf, err := r.readAt(0, lenHeader)
  118 + if err != nil {
  119 + return err
  120 + }
  121 + r.header = &header{headerFields: makeHeader(buf)}
  122 + // sanity check - check signature
  123 + if r.header.signature != signature {
  124 + return Error{ErrFormat, "bad signature", int64(r.header.signature)}
  125 + }
  126 + // check for legal sector size
  127 + if r.header.sectorSize == 0x0009 || r.header.sectorSize == 0x000c {
  128 + r.sectorSize = uint32(1 << r.header.sectorSize)
  129 + } else {
  130 + return Error{ErrFormat, "illegal sector size", int64(r.header.sectorSize)}
  131 + }
  132 + // check for DIFAT overflow
  133 + if r.header.numDifatSectors > 0 {
  134 + sz := (r.sectorSize / 4) - 1
  135 + if int(r.header.numDifatSectors*sz+109) < 0 {
  136 + return Error{ErrFormat, "DIFAT int overflow", int64(r.header.numDifatSectors)}
  137 + }
  138 + if r.header.numDifatSectors*sz+109 > r.header.numFatSectors+sz {
  139 + return Error{ErrFormat, "num DIFATs exceeds FAT sectors", int64(r.header.numDifatSectors)}
  140 + }
  141 + }
  142 + // check for mini FAT overflow
  143 + if r.header.numMiniFatSectors > 0 {
  144 + if int(r.sectorSize/4*r.header.numMiniFatSectors) < 0 {
  145 + return Error{ErrFormat, "mini FAT int overflow", int64(r.header.numMiniFatSectors)}
  146 + }
  147 + if r.header.numMiniFatSectors > r.header.numFatSectors*(r.sectorSize/miniStreamSectorSize) {
  148 + return Error{ErrFormat, "num mini FATs exceeds FAT sectors", int64(r.header.numFatSectors)}
  149 + }
  150 + }
  151 + return nil
  152 +}
  153 +
  154 +func (r *Reader) setDifats() error {
  155 + r.header.difats = r.header.initialDifats[:]
  156 + // return early if no extra DIFAT sectors
  157 + if r.header.numDifatSectors == 0 {
  158 + return nil
  159 + }
  160 + sz := (r.sectorSize / 4) - 1
  161 + n := make([]uint32, 109, r.header.numDifatSectors*sz+109)
  162 + copy(n, r.header.difats)
  163 + r.header.difats = n
  164 + off := r.header.difatSectorLoc
  165 + for i := 0; i < int(r.header.numDifatSectors); i++ {
  166 + buf, err := r.readAt(fileOffset(r.sectorSize, off), int(r.sectorSize))
  167 + if err != nil {
  168 + return Error{ErrFormat, "error setting DIFAT(" + err.Error() + ")", int64(off)}
  169 + }
  170 + for j := 0; j < int(sz); j++ {
  171 + r.header.difats = append(r.header.difats, binary.LittleEndian.Uint32(buf[j*4:j*4+4]))
  172 + }
  173 + off = binary.LittleEndian.Uint32(buf[len(buf)-4:])
  174 + }
  175 + return nil
  176 +}
  177 +
  178 +// set the ministream FAT and sector slices in the header
  179 +func (r *Reader) setMiniStream() error {
  180 + // do nothing if there is no ministream
  181 + if r.direntries[0].startingSectorLoc == endOfChain || r.header.miniFatSectorLoc == endOfChain || r.header.numMiniFatSectors == 0 {
  182 + return nil
  183 + }
  184 + // build a slice of minifat sectors (akin to the DIFAT slice)
  185 + c := int(r.header.numMiniFatSectors)
  186 + r.header.miniFatLocs = make([]uint32, c)
  187 + r.header.miniFatLocs[0] = r.header.miniFatSectorLoc
  188 + for i := 1; i < c; i++ {
  189 + loc, err := r.findNext(r.header.miniFatLocs[i-1], false)
  190 + if err != nil {
  191 + return Error{ErrFormat, "setting mini stream (" + err.Error() + ")", int64(r.header.miniFatLocs[i-1])}
  192 + }
  193 + r.header.miniFatLocs[i] = loc
  194 + }
  195 + // build a slice of ministream sectors
  196 + c = int(r.sectorSize / 4 * r.header.numMiniFatSectors)
  197 + r.header.miniStreamLocs = make([]uint32, 0, c)
  198 + sn := r.direntries[0].startingSectorLoc
  199 + var err error
  200 + for sn != endOfChain {
  201 + r.header.miniStreamLocs = append(r.header.miniStreamLocs, sn)
  202 + sn, err = r.findNext(sn, false)
  203 + if err != nil {
  204 + return Error{ErrFormat, "setting mini stream (" + err.Error() + ")", int64(sn)}
  205 + }
  206 + }
  207 + return nil
  208 +}
  209 +
  210 +func (r *Reader) readAt(offset int64, length int) ([]byte, error) {
  211 + if r.slicer {
  212 + b, err := r.ra.(slicer).Slice(offset, length)
  213 + if err != nil {
  214 + return nil, Error{ErrRead, "slicer read error (" + err.Error() + ")", offset}
  215 + }
  216 + return b, nil
  217 + }
  218 + if length > len(r.buf) {
  219 + return nil, Error{ErrRead, "read length greater than read buffer", int64(length)}
  220 + }
  221 + if _, err := r.ra.ReadAt(r.buf[:length], offset); err != nil {
  222 + return nil, Error{ErrRead, err.Error(), offset}
  223 + }
  224 + return r.buf[:length], nil
  225 +}
  226 +
  227 +func (r *Reader) getOffset(sn uint32, mini bool) (int64, error) {
  228 + if mini {
  229 + num := r.sectorSize / 64
  230 + sec := int(sn / num)
  231 + if sec >= len(r.header.miniStreamLocs) {
  232 + return 0, Error{ErrRead, "minisector number is outside minisector range", int64(sec)}
  233 + }
  234 + dif := sn % num
  235 + return int64((r.header.miniStreamLocs[sec]+1)*r.sectorSize + dif*64), nil
  236 + }
  237 + return fileOffset(r.sectorSize, sn), nil
  238 +}
  239 +
  240 +// check the FAT sector for the next sector in a chain
  241 +func (r *Reader) findNext(sn uint32, mini bool) (uint32, error) {
  242 + entries := r.sectorSize / 4
  243 + index := int(sn / entries) // find position in DIFAT or minifat array
  244 + var sect uint32
  245 + if mini {
  246 + if index < 0 || index >= len(r.header.miniFatLocs) {
  247 + return 0, Error{ErrRead, "minisector index is outside miniFAT range", int64(index)}
  248 + }
  249 + sect = r.header.miniFatLocs[index]
  250 + } else {
  251 + if index < 0 || index >= len(r.header.difats) {
  252 + return 0, Error{ErrRead, "FAT index is outside DIFAT range", int64(index)}
  253 + }
  254 + sect = r.header.difats[index]
  255 + }
  256 + fatIndex := sn % entries // find position within FAT or MiniFAT sector
  257 + offset := fileOffset(r.sectorSize, sect) + int64(fatIndex*4)
  258 + buf, err := r.readAt(offset, 4)
  259 + if err != nil {
  260 + return 0, Error{ErrRead, "bad read finding next sector (" + err.Error() + ")", offset}
  261 + }
  262 + return binary.LittleEndian.Uint32(buf), nil
  263 +}
  264 +
  265 +// Reader provides sequential access to the contents of a MS compound file (MSCFB)
  266 +type Reader struct {
  267 + slicer bool
  268 + sectorSize uint32
  269 + buf []byte
  270 + header *header
  271 + File []*File // File is an ordered slice of final directory entries.
  272 + direntries []*File // unordered raw directory entries
  273 + entry int
  274 +
  275 + ra io.ReaderAt
  276 + wa io.WriterAt
  277 +}
  278 +
  279 +// New returns a MSCFB reader
  280 +func New(ra io.ReaderAt) (*Reader, error) {
  281 + r := &Reader{ra: ra}
  282 + if _, ok := ra.(slicer); ok {
  283 + r.slicer = true
  284 + } else {
  285 + r.buf = make([]byte, lenHeader)
  286 + }
  287 + if err := r.setHeader(); err != nil {
  288 + return nil, err
  289 + }
  290 + // resize the buffer to 4096 if sector size isn't 512
  291 + if !r.slicer && int(r.sectorSize) > len(r.buf) {
  292 + r.buf = make([]byte, r.sectorSize)
  293 + }
  294 + if err := r.setDifats(); err != nil {
  295 + return nil, err
  296 + }
  297 + if err := r.setDirEntries(); err != nil {
  298 + return nil, err
  299 + }
  300 + if err := r.setMiniStream(); err != nil {
  301 + return nil, err
  302 + }
  303 + if err := r.traverse(); err != nil {
  304 + return nil, err
  305 + }
  306 + return r, nil
  307 +}
  308 +
  309 +// ID returns the CLSID (class ID) field from the root directory entry
  310 +func (r *Reader) ID() string {
  311 + return r.File[0].ID()
  312 +}
  313 +
  314 +// Created returns the created field from the root directory entry
  315 +func (r *Reader) Created() time.Time {
  316 + return r.File[0].Created()
  317 +}
  318 +
  319 +// Modified returns the last modified field from the root directory entry
  320 +func (r *Reader) Modified() time.Time {
  321 + return r.File[0].Modified()
  322 +}
  323 +
  324 +// Next iterates to the next directory entry.
  325 +// This isn't necessarily an adjacent *File within the File slice, but is based on the Left Sibling, Right Sibling and Child information in directory entries.
  326 +func (r *Reader) Next() (*File, error) {
  327 + r.entry++
  328 + if r.entry >= len(r.File) {
  329 + return nil, io.EOF
  330 + }
  331 + return r.File[r.entry], nil
  332 +}
  333 +
  334 +// Read the current directory entry
  335 +func (r *Reader) Read(b []byte) (n int, err error) {
  336 + if r.entry >= len(r.File) {
  337 + return 0, io.EOF
  338 + }
  339 + return r.File[r.entry].Read(b)
  340 +}
  341 +
  342 +// Debug provides granular information from an mscfb file to assist with debugging
  343 +func (r *Reader) Debug() map[string][]uint32 {
  344 + ret := map[string][]uint32{
  345 + "sector size": []uint32{r.sectorSize},
  346 + "mini fat locs": r.header.miniFatLocs,
  347 + "mini stream locs": r.header.miniStreamLocs,
  348 + "directory sector": []uint32{r.header.directorySectorLoc},
  349 + "mini stream start/size": []uint32{r.File[0].startingSectorLoc, binary.LittleEndian.Uint32(r.File[0].streamSize[:])},
  350 + }
  351 + for f, err := r.Next(); err == nil; f, err = r.Next() {
  352 + ret[f.Name+" start/size"] = []uint32{f.startingSectorLoc, binary.LittleEndian.Uint32(f.streamSize[:])}
  353 + }
  354 + return ret
  355 +}
  356 +
  357 +const (
  358 + // ErrFormat reports issues with the MSCFB's header structures
  359 + ErrFormat = iota
  360 + // ErrRead reports issues attempting to read MSCFB streams
  361 + ErrRead
  362 + // ErrSeek reports seek issues
  363 + ErrSeek
  364 + // ErrWrite reports write issues
  365 + ErrWrite
  366 + // ErrTraverse reports issues attempting to traverse the child-parent-sibling relations
  367 + // between MSCFB storage objects
  368 + ErrTraverse
  369 +)
  370 +
  371 +type Error struct {
  372 + typ int
  373 + msg string
  374 + val int64
  375 +}
  376 +
  377 +func (e Error) Error() string {
  378 + return "mscfb: " + e.msg + "; " + strconv.FormatInt(e.val, 10)
  379 +}
  380 +
  381 +// Typ gives the type of MSCFB error
  382 +func (e Error) Typ() int {
  383 + return e.typ
  384 +}
  385 +
  386 +// Slicer interface avoids a copy by obtaining a byte slice directly from the underlying reader
  387 +type slicer interface {
  388 + Slice(offset int64, length int) ([]byte, error)
  389 +}
1 -// Copyright 2014 Richard Lehane. All rights reserved.  
2 -//  
3 -// Licensed under the Apache License, Version 2.0 (the "License");  
4 -// you may not use this file except in compliance with the License.  
5 -// You may obtain a copy of the License at  
6 -//  
7 -// http://www.apache.org/licenses/LICENSE-2.0  
8 -//  
9 -// Unless required by applicable law or agreed to in writing, software  
10 -// distributed under the License is distributed on an "AS IS" BASIS,  
11 -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  
12 -// See the License for the specific language governing permissions and  
13 -// limitations under the License.  
14 -  
15 -package types  
16 -  
17 -import (  
18 - "encoding/binary"  
19 - "strconv"  
20 -)  
21 -  
22 -//The CURRENCY type specifies currency information. It is represented as an 8-byte integer, scaled by 10,000, to give a fixed-point number with 15 digits to the left of the decimal point, and four digits to the right. This representation provides a range of 922337203685477.5807 to –922337203685477.5808. For example, $5.25 is stored as the value 52500.  
23 -  
24 -type Currency int64  
25 -  
26 -func (c Currency) String() string {  
27 - return "$" + strconv.FormatFloat(float64(c)/10000, 'f', -1, 64)  
28 -}  
29 -  
30 -func (c Currency) Type() string {  
31 - return "Currency"  
32 -}  
33 -  
34 -func (c Currency) Length() int {  
35 - return 8  
36 -}  
37 -  
38 -func MakeCurrency(b []byte) (Type, error) {  
39 - if len(b) < 8 {  
40 - return Currency(0), ErrType  
41 - }  
42 - return Currency(binary.LittleEndian.Uint64(b[:8])), nil  
43 -} 1 +// Copyright 2014 Richard Lehane. All rights reserved.
  2 +//
  3 +// Licensed under the Apache License, Version 2.0 (the "License");
  4 +// you may not use this file except in compliance with the License.
  5 +// You may obtain a copy of the License at
  6 +//
  7 +// http://www.apache.org/licenses/LICENSE-2.0
  8 +//
  9 +// Unless required by applicable law or agreed to in writing, software
  10 +// distributed under the License is distributed on an "AS IS" BASIS,
  11 +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12 +// See the License for the specific language governing permissions and
  13 +// limitations under the License.
  14 +
  15 +package types
  16 +
  17 +import (
  18 + "encoding/binary"
  19 + "strconv"
  20 +)
  21 +
  22 +//The CURRENCY type specifies currency information. It is represented as an 8-byte integer, scaled by 10,000, to give a fixed-point number with 15 digits to the left of the decimal point, and four digits to the right. This representation provides a range of 922337203685477.5807 to –922337203685477.5808. For example, $5.25 is stored as the value 52500.
  23 +
  24 +type Currency int64
  25 +
  26 +func (c Currency) String() string {
  27 + return "$" + strconv.FormatFloat(float64(c)/10000, 'f', -1, 64)
  28 +}
  29 +
  30 +func (c Currency) Type() string {
  31 + return "Currency"
  32 +}
  33 +
  34 +func (c Currency) Length() int {
  35 + return 8
  36 +}
  37 +
  38 +func MakeCurrency(b []byte) (Type, error) {
  39 + if len(b) < 8 {
  40 + return Currency(0), ErrType
  41 + }
  42 + return Currency(binary.LittleEndian.Uint64(b[:8])), nil
  43 +}
1 -// Copyright 2014 Richard Lehane. All rights reserved.  
2 -//  
3 -// Licensed under the Apache License, Version 2.0 (the "License");  
4 -// you may not use this file except in compliance with the License.  
5 -// You may obtain a copy of the License at  
6 -//  
7 -// http://www.apache.org/licenses/LICENSE-2.0  
8 -//  
9 -// Unless required by applicable law or agreed to in writing, software  
10 -// distributed under the License is distributed on an "AS IS" BASIS,  
11 -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  
12 -// See the License for the specific language governing permissions and  
13 -// limitations under the License.  
14 -  
15 -package types  
16 -  
17 -import (  
18 - "encoding/binary"  
19 - "time"  
20 -)  
21 -  
22 -// http://msdn.microsoft.com/en-us/library/cc237601.aspx  
23 -type Date float64  
24 -  
25 -func (d Date) Time() time.Time {  
26 - start := time.Date(1899, 12, 30, 0, 0, 0, 0, time.UTC)  
27 - day := float64(time.Hour * 24)  
28 - dur := time.Duration(day * float64(d))  
29 - return start.Add(dur)  
30 -}  
31 -  
32 -func (d Date) String() string {  
33 - return d.Time().String()  
34 -}  
35 -  
36 -func (d Date) Type() string {  
37 - return "Date"  
38 -}  
39 -  
40 -func (d Date) Length() int {  
41 - return 8  
42 -}  
43 -  
44 -func MakeDate(b []byte) (Type, error) {  
45 - if len(b) < 8 {  
46 - return Date(0), ErrType  
47 - }  
48 - return Date(binary.LittleEndian.Uint64(b[:8])), nil  
49 -} 1 +// Copyright 2014 Richard Lehane. All rights reserved.
  2 +//
  3 +// Licensed under the Apache License, Version 2.0 (the "License");
  4 +// you may not use this file except in compliance with the License.
  5 +// You may obtain a copy of the License at
  6 +//
  7 +// http://www.apache.org/licenses/LICENSE-2.0
  8 +//
  9 +// Unless required by applicable law or agreed to in writing, software
  10 +// distributed under the License is distributed on an "AS IS" BASIS,
  11 +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12 +// See the License for the specific language governing permissions and
  13 +// limitations under the License.
  14 +
  15 +package types
  16 +
  17 +import (
  18 + "encoding/binary"
  19 + "time"
  20 +)
  21 +
  22 +// http://msdn.microsoft.com/en-us/library/cc237601.aspx
  23 +type Date float64
  24 +
  25 +func (d Date) Time() time.Time {
  26 + start := time.Date(1899, 12, 30, 0, 0, 0, 0, time.UTC)
  27 + day := float64(time.Hour * 24)
  28 + dur := time.Duration(day * float64(d))
  29 + return start.Add(dur)
  30 +}
  31 +
  32 +func (d Date) String() string {
  33 + return d.Time().String()
  34 +}
  35 +
  36 +func (d Date) Type() string {
  37 + return "Date"
  38 +}
  39 +
  40 +func (d Date) Length() int {
  41 + return 8
  42 +}
  43 +
  44 +func MakeDate(b []byte) (Type, error) {
  45 + if len(b) < 8 {
  46 + return Date(0), ErrType
  47 + }
  48 + return Date(binary.LittleEndian.Uint64(b[:8])), nil
  49 +}
1 -// Copyright 2014 Richard Lehane. All rights reserved.  
2 -//  
3 -// Licensed under the Apache License, Version 2.0 (the "License");  
4 -// you may not use this file except in compliance with the License.  
5 -// You may obtain a copy of the License at  
6 -//  
7 -// http://www.apache.org/licenses/LICENSE-2.0  
8 -//  
9 -// Unless required by applicable law or agreed to in writing, software  
10 -// distributed under the License is distributed on an "AS IS" BASIS,  
11 -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  
12 -// See the License for the specific language governing permissions and  
13 -// limitations under the License.  
14 -  
15 -package types  
16 -  
17 -import (  
18 - "encoding/binary"  
19 - "math"  
20 - "math/big"  
21 -)  
22 -  
23 -// http://msdn.microsoft.com/en-us/library/cc237603.aspx  
24 -type Decimal struct {  
25 - res [2]byte  
26 - scale byte  
27 - sign byte  
28 - high32 uint32  
29 - low64 uint64  
30 -}  
31 -  
32 -func (d Decimal) Type() string {  
33 - return "Decimal"  
34 -}  
35 -  
36 -func (d Decimal) Length() int {  
37 - return 16  
38 -}  
39 -  
40 -func (d Decimal) String() string {  
41 - h, l, b := new(big.Int), new(big.Int), new(big.Int)  
42 - l.SetUint64(d.low64)  
43 - h.Lsh(big.NewInt(int64(d.high32)), 64)  
44 - b.Add(h, l)  
45 - q, f, r := new(big.Rat), new(big.Rat), new(big.Rat)  
46 - q.SetFloat64(math.Pow10(int(d.scale)))  
47 - r.Quo(f.SetInt(b), q)  
48 - if d.sign == 0x80 {  
49 - r.Neg(r)  
50 - }  
51 - return r.FloatString(20)  
52 -}  
53 -  
54 -func MakeDecimal(b []byte) (Type, error) {  
55 - if len(b) < 16 {  
56 - return Decimal{}, ErrType  
57 - }  
58 - return Decimal{  
59 - res: [2]byte{b[0], b[1]},  
60 - scale: b[2],  
61 - sign: b[3],  
62 - high32: binary.LittleEndian.Uint32(b[4:8]),  
63 - low64: binary.LittleEndian.Uint64(b[8:16]),  
64 - }, nil  
65 -} 1 +// Copyright 2014 Richard Lehane. All rights reserved.
  2 +//
  3 +// Licensed under the Apache License, Version 2.0 (the "License");
  4 +// you may not use this file except in compliance with the License.
  5 +// You may obtain a copy of the License at
  6 +//
  7 +// http://www.apache.org/licenses/LICENSE-2.0
  8 +//
  9 +// Unless required by applicable law or agreed to in writing, software
  10 +// distributed under the License is distributed on an "AS IS" BASIS,
  11 +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12 +// See the License for the specific language governing permissions and
  13 +// limitations under the License.
  14 +
  15 +package types
  16 +
  17 +import (
  18 + "encoding/binary"
  19 + "math"
  20 + "math/big"
  21 +)
  22 +
  23 +// http://msdn.microsoft.com/en-us/library/cc237603.aspx
  24 +type Decimal struct {
  25 + res [2]byte
  26 + scale byte
  27 + sign byte
  28 + high32 uint32
  29 + low64 uint64
  30 +}
  31 +
  32 +func (d Decimal) Type() string {
  33 + return "Decimal"
  34 +}
  35 +
  36 +func (d Decimal) Length() int {
  37 + return 16
  38 +}
  39 +
  40 +func (d Decimal) String() string {
  41 + h, l, b := new(big.Int), new(big.Int), new(big.Int)
  42 + l.SetUint64(d.low64)
  43 + h.Lsh(big.NewInt(int64(d.high32)), 64)
  44 + b.Add(h, l)
  45 + q, f, r := new(big.Rat), new(big.Rat), new(big.Rat)
  46 + q.SetFloat64(math.Pow10(int(d.scale)))
  47 + r.Quo(f.SetInt(b), q)
  48 + if d.sign == 0x80 {
  49 + r.Neg(r)
  50 + }
  51 + return r.FloatString(20)
  52 +}
  53 +
  54 +func MakeDecimal(b []byte) (Type, error) {
  55 + if len(b) < 16 {
  56 + return Decimal{}, ErrType
  57 + }
  58 + return Decimal{
  59 + res: [2]byte{b[0], b[1]},
  60 + scale: b[2],
  61 + sign: b[3],
  62 + high32: binary.LittleEndian.Uint32(b[4:8]),
  63 + low64: binary.LittleEndian.Uint64(b[8:16]),
  64 + }, nil
  65 +}
1 -// Copyright 2014 Richard Lehane. All rights reserved.  
2 -//  
3 -// Licensed under the Apache License, Version 2.0 (the "License");  
4 -// you may not use this file except in compliance with the License.  
5 -// You may obtain a copy of the License at  
6 -//  
7 -// http://www.apache.org/licenses/LICENSE-2.0  
8 -//  
9 -// Unless required by applicable law or agreed to in writing, software  
10 -// distributed under the License is distributed on an "AS IS" BASIS,  
11 -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  
12 -// See the License for the specific language governing permissions and  
13 -// limitations under the License.  
14 -  
15 -package types  
16 -  
17 -import (  
18 - "encoding/binary"  
19 - "time"  
20 -)  
21 -  
22 -// Win FILETIME type  
23 -// http://msdn.microsoft.com/en-us/library/cc230324.aspx  
24 -type FileTime struct {  
25 - Low uint32 // Windows FILETIME structure  
26 - High uint32 // Windows FILETIME structure  
27 -}  
28 -  
29 -const (  
30 - tick uint64 = 10000000  
31 - gregToUnix uint64 = 11644473600  
32 -)  
33 -  
34 -func winToUnix(low, high uint32) int64 {  
35 - gregTime := ((uint64(high) << 32) + uint64(low)) / tick  
36 - if gregTime < gregToUnix {  
37 - return 0  
38 - }  
39 - return int64(gregTime - gregToUnix)  
40 -}  
41 -  
42 -func (f FileTime) Time() time.Time {  
43 - return time.Unix(winToUnix(f.Low, f.High), 0)  
44 -}  
45 -  
46 -func (f FileTime) String() string {  
47 - return f.Time().String()  
48 -}  
49 -  
50 -func (f FileTime) Type() string {  
51 - return "FileTime"  
52 -}  
53 -  
54 -func (f FileTime) Length() int {  
55 - return 8  
56 -}  
57 -  
58 -func MakeFileTime(b []byte) (Type, error) {  
59 - if len(b) < 8 {  
60 - return FileTime{}, ErrType  
61 - }  
62 - return MustFileTime(b), nil  
63 -}  
64 -  
65 -func MustFileTime(b []byte) FileTime {  
66 - return FileTime{  
67 - Low: binary.LittleEndian.Uint32(b[:4]),  
68 - High: binary.LittleEndian.Uint32(b[4:8]),  
69 - }  
70 -} 1 +// Copyright 2014 Richard Lehane. All rights reserved.
  2 +//
  3 +// Licensed under the Apache License, Version 2.0 (the "License");
  4 +// you may not use this file except in compliance with the License.
  5 +// You may obtain a copy of the License at
  6 +//
  7 +// http://www.apache.org/licenses/LICENSE-2.0
  8 +//
  9 +// Unless required by applicable law or agreed to in writing, software
  10 +// distributed under the License is distributed on an "AS IS" BASIS,
  11 +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12 +// See the License for the specific language governing permissions and
  13 +// limitations under the License.
  14 +
  15 +package types
  16 +
  17 +import (
  18 + "encoding/binary"
  19 + "time"
  20 +)
  21 +
  22 +// Win FILETIME type
  23 +// http://msdn.microsoft.com/en-us/library/cc230324.aspx
  24 +type FileTime struct {
  25 + Low uint32 // Windows FILETIME structure
  26 + High uint32 // Windows FILETIME structure
  27 +}
  28 +
  29 +const (
  30 + tick uint64 = 10000000
  31 + gregToUnix uint64 = 11644473600
  32 +)
  33 +
  34 +func winToUnix(low, high uint32) int64 {
  35 + gregTime := ((uint64(high) << 32) + uint64(low)) / tick
  36 + if gregTime < gregToUnix {
  37 + return 0
  38 + }
  39 + return int64(gregTime - gregToUnix)
  40 +}
  41 +
  42 +func (f FileTime) Time() time.Time {
  43 + return time.Unix(winToUnix(f.Low, f.High), 0)
  44 +}
  45 +
  46 +func (f FileTime) String() string {
  47 + return f.Time().String()
  48 +}
  49 +
  50 +func (f FileTime) Type() string {
  51 + return "FileTime"
  52 +}
  53 +
  54 +func (f FileTime) Length() int {
  55 + return 8
  56 +}
  57 +
  58 +func MakeFileTime(b []byte) (Type, error) {
  59 + if len(b) < 8 {
  60 + return FileTime{}, ErrType
  61 + }
  62 + return MustFileTime(b), nil
  63 +}
  64 +
  65 +func MustFileTime(b []byte) FileTime {
  66 + return FileTime{
  67 + Low: binary.LittleEndian.Uint32(b[:4]),
  68 + High: binary.LittleEndian.Uint32(b[4:8]),
  69 + }
  70 +}
1 -// Copyright 2014 Richard Lehane. All rights reserved.  
2 -//  
3 -// Licensed under the Apache License, Version 2.0 (the "License");  
4 -// you may not use this file except in compliance with the License.  
5 -// You may obtain a copy of the License at  
6 -//  
7 -// http://www.apache.org/licenses/LICENSE-2.0  
8 -//  
9 -// Unless required by applicable law or agreed to in writing, software  
10 -// distributed under the License is distributed on an "AS IS" BASIS,  
11 -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  
12 -// See the License for the specific language governing permissions and  
13 -// limitations under the License.  
14 -  
15 -package types  
16 -  
17 -import (  
18 - "encoding/binary"  
19 - "encoding/hex"  
20 - "errors"  
21 - "strings"  
22 -)  
23 -  
24 -// Win GUID and UUID type  
25 -// http://msdn.microsoft.com/en-us/library/cc230326.aspx  
26 -type Guid struct {  
27 - DataA uint32  
28 - DataB uint16  
29 - DataC uint16  
30 - DataD [8]byte  
31 -}  
32 -  
33 -func (g Guid) String() string {  
34 - buf := make([]byte, 8)  
35 - binary.BigEndian.PutUint32(buf[:4], g.DataA)  
36 - binary.BigEndian.PutUint16(buf[4:6], g.DataB)  
37 - binary.BigEndian.PutUint16(buf[6:], g.DataC)  
38 - return strings.ToUpper("{" +  
39 - hex.EncodeToString(buf[:4]) +  
40 - "-" +  
41 - hex.EncodeToString(buf[4:6]) +  
42 - "-" +  
43 - hex.EncodeToString(buf[6:]) +  
44 - "-" +  
45 - hex.EncodeToString(g.DataD[:2]) +  
46 - "-" +  
47 - hex.EncodeToString(g.DataD[2:]) +  
48 - "}")  
49 -}  
50 -  
51 -func (g Guid) Type() string {  
52 - return "Guid"  
53 -}  
54 -  
55 -func (g Guid) Length() int {  
56 - return 16  
57 -}  
58 -  
59 -func GuidFromString(str string) (Guid, error) {  
60 - gerr := "Invalid GUID: expecting in format {F29F85E0-4FF9-1068-AB91-08002B27B3D9}, got " + str  
61 - if len(str) != 38 {  
62 - return Guid{}, errors.New(gerr + "; bad length, should be 38 chars")  
63 - }  
64 - trimmed := strings.Trim(str, "{}")  
65 - parts := strings.Split(trimmed, "-")  
66 - if len(parts) != 5 {  
67 - return Guid{}, errors.New(gerr + "; expecting should five '-' separators")  
68 - }  
69 - buf, err := hex.DecodeString(strings.Join(parts, ""))  
70 - if err != nil {  
71 - return Guid{}, errors.New(gerr + "; error decoding hex: " + err.Error())  
72 - }  
73 - return makeGuid(buf, binary.BigEndian), nil  
74 -}  
75 -  
76 -func MakeGuid(b []byte) (Type, error) {  
77 - if len(b) < 16 {  
78 - return Guid{}, ErrType  
79 - }  
80 - return makeGuid(b, binary.LittleEndian), nil  
81 -}  
82 -  
83 -func makeGuid(b []byte, order binary.ByteOrder) Guid {  
84 - g := Guid{  
85 - DataA: order.Uint32(b[:4]),  
86 - DataB: order.Uint16(b[4:6]),  
87 - DataC: order.Uint16(b[6:8]),  
88 - DataD: [8]byte{},  
89 - }  
90 - copy(g.DataD[:], b[8:])  
91 - return g  
92 -}  
93 -  
94 -func MustGuidFromString(str string) Guid {  
95 - g, err := GuidFromString(str)  
96 - if err != nil {  
97 - panic(err)  
98 - }  
99 - return g  
100 -}  
101 -  
102 -func MustGuid(b []byte) Guid {  
103 - return makeGuid(b, binary.LittleEndian)  
104 -}  
105 -  
106 -func GuidFromName(n string) (Guid, error) {  
107 - n = strings.ToLower(n)  
108 - buf, err := charConvert([]byte(n))  
109 - if err != nil {  
110 - return Guid{}, err  
111 - }  
112 - return makeGuid(buf, binary.LittleEndian), nil  
113 -}  
114 -  
115 -func charConvert(in []byte) ([]byte, error) {  
116 - if len(in) != 26 {  
117 - return nil, errors.New("invalid GUID: expecting 26 characters")  
118 - }  
119 - out := make([]byte, 16)  
120 - var idx, shift uint  
121 - var b byte  
122 - for _, v := range in {  
123 - this, ok := characterMapping[v]  
124 - if !ok {  
125 - return nil, errors.New("invalid Guid: invalid character")  
126 - }  
127 - b = b | this<<shift  
128 - if shift >= 3 {  
129 - out[idx] = b  
130 - idx++  
131 - b = this >> (8 - shift) // write any remainder back to b, or 0 if shift is 3  
132 - }  
133 - shift = shift + 5  
134 - if shift > 7 {  
135 - shift = shift - 8  
136 - }  
137 - }  
138 - return out, nil  
139 -}  
140 -  
141 -const (  
142 - charA byte = iota  
143 - charB  
144 - charC  
145 - charD  
146 - charE  
147 - charF  
148 - charG  
149 - charH  
150 - charI  
151 - charJ  
152 - charK  
153 - charL  
154 - charM  
155 - charN  
156 - charO  
157 - charP  
158 - charQ  
159 - charR  
160 - charS  
161 - charT  
162 - charU  
163 - charV  
164 - charW  
165 - charX  
166 - charY  
167 - charZ  
168 - char0  
169 - char1  
170 - char2  
171 - char3  
172 - char4  
173 - char5  
174 -)  
175 -  
176 -var characterMapping = map[byte]byte{  
177 - 'a': charA,  
178 - 'b': charB,  
179 - 'c': charC,  
180 - 'd': charD,  
181 - 'e': charE,  
182 - 'f': charF,  
183 - 'g': charG,  
184 - 'h': charH,  
185 - 'i': charI,  
186 - 'j': charJ,  
187 - 'k': charK,  
188 - 'l': charL,  
189 - 'm': charM,  
190 - 'n': charN,  
191 - 'o': charO,  
192 - 'p': charP,  
193 - 'q': charQ,  
194 - 'r': charR,  
195 - 's': charS,  
196 - 't': charT,  
197 - 'u': charU,  
198 - 'v': charV,  
199 - 'w': charW,  
200 - 'x': charX,  
201 - 'y': charY,  
202 - 'z': charZ,  
203 - '0': char0,  
204 - '1': char1,  
205 - '2': char2,  
206 - '3': char3,  
207 - '4': char4,  
208 - '5': char5,  
209 -} 1 +// Copyright 2014 Richard Lehane. All rights reserved.
  2 +//
  3 +// Licensed under the Apache License, Version 2.0 (the "License");
  4 +// you may not use this file except in compliance with the License.
  5 +// You may obtain a copy of the License at
  6 +//
  7 +// http://www.apache.org/licenses/LICENSE-2.0
  8 +//
  9 +// Unless required by applicable law or agreed to in writing, software
  10 +// distributed under the License is distributed on an "AS IS" BASIS,
  11 +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12 +// See the License for the specific language governing permissions and
  13 +// limitations under the License.
  14 +
  15 +package types
  16 +
  17 +import (
  18 + "encoding/binary"
  19 + "encoding/hex"
  20 + "errors"
  21 + "strings"
  22 +)
  23 +
  24 +// Win GUID and UUID type
  25 +// http://msdn.microsoft.com/en-us/library/cc230326.aspx
  26 +type Guid struct {
  27 + DataA uint32
  28 + DataB uint16
  29 + DataC uint16
  30 + DataD [8]byte
  31 +}
  32 +
  33 +func (g Guid) String() string {
  34 + buf := make([]byte, 8)
  35 + binary.BigEndian.PutUint32(buf[:4], g.DataA)
  36 + binary.BigEndian.PutUint16(buf[4:6], g.DataB)
  37 + binary.BigEndian.PutUint16(buf[6:], g.DataC)
  38 + return strings.ToUpper("{" +
  39 + hex.EncodeToString(buf[:4]) +
  40 + "-" +
  41 + hex.EncodeToString(buf[4:6]) +
  42 + "-" +
  43 + hex.EncodeToString(buf[6:]) +
  44 + "-" +
  45 + hex.EncodeToString(g.DataD[:2]) +
  46 + "-" +
  47 + hex.EncodeToString(g.DataD[2:]) +
  48 + "}")
  49 +}
  50 +
  51 +func (g Guid) Type() string {
  52 + return "Guid"
  53 +}
  54 +
  55 +func (g Guid) Length() int {
  56 + return 16
  57 +}
  58 +
  59 +func GuidFromString(str string) (Guid, error) {
  60 + gerr := "Invalid GUID: expecting in format {F29F85E0-4FF9-1068-AB91-08002B27B3D9}, got " + str
  61 + if len(str) != 38 {
  62 + return Guid{}, errors.New(gerr + "; bad length, should be 38 chars")
  63 + }
  64 + trimmed := strings.Trim(str, "{}")
  65 + parts := strings.Split(trimmed, "-")
  66 + if len(parts) != 5 {
  67 + return Guid{}, errors.New(gerr + "; expecting should five '-' separators")
  68 + }
  69 + buf, err := hex.DecodeString(strings.Join(parts, ""))
  70 + if err != nil {
  71 + return Guid{}, errors.New(gerr + "; error decoding hex: " + err.Error())
  72 + }
  73 + return makeGuid(buf, binary.BigEndian), nil
  74 +}
  75 +
  76 +func MakeGuid(b []byte) (Type, error) {
  77 + if len(b) < 16 {
  78 + return Guid{}, ErrType
  79 + }
  80 + return makeGuid(b, binary.LittleEndian), nil
  81 +}
  82 +
  83 +func makeGuid(b []byte, order binary.ByteOrder) Guid {
  84 + g := Guid{
  85 + DataA: order.Uint32(b[:4]),
  86 + DataB: order.Uint16(b[4:6]),
  87 + DataC: order.Uint16(b[6:8]),
  88 + DataD: [8]byte{},
  89 + }
  90 + copy(g.DataD[:], b[8:])
  91 + return g
  92 +}
  93 +
  94 +func MustGuidFromString(str string) Guid {
  95 + g, err := GuidFromString(str)
  96 + if err != nil {
  97 + panic(err)
  98 + }
  99 + return g
  100 +}
  101 +
  102 +func MustGuid(b []byte) Guid {
  103 + return makeGuid(b, binary.LittleEndian)
  104 +}
  105 +
  106 +func GuidFromName(n string) (Guid, error) {
  107 + n = strings.ToLower(n)
  108 + buf, err := charConvert([]byte(n))
  109 + if err != nil {
  110 + return Guid{}, err
  111 + }
  112 + return makeGuid(buf, binary.LittleEndian), nil
  113 +}
  114 +
  115 +func charConvert(in []byte) ([]byte, error) {
  116 + if len(in) != 26 {
  117 + return nil, errors.New("invalid GUID: expecting 26 characters")
  118 + }
  119 + out := make([]byte, 16)
  120 + var idx, shift uint
  121 + var b byte
  122 + for _, v := range in {
  123 + this, ok := characterMapping[v]
  124 + if !ok {
  125 + return nil, errors.New("invalid Guid: invalid character")
  126 + }
  127 + b = b | this<<shift
  128 + if shift >= 3 {
  129 + out[idx] = b
  130 + idx++
  131 + b = this >> (8 - shift) // write any remainder back to b, or 0 if shift is 3
  132 + }
  133 + shift = shift + 5
  134 + if shift > 7 {
  135 + shift = shift - 8
  136 + }
  137 + }
  138 + return out, nil
  139 +}
  140 +
  141 +const (
  142 + charA byte = iota
  143 + charB
  144 + charC
  145 + charD
  146 + charE
  147 + charF
  148 + charG
  149 + charH
  150 + charI
  151 + charJ
  152 + charK
  153 + charL
  154 + charM
  155 + charN
  156 + charO
  157 + charP
  158 + charQ
  159 + charR
  160 + charS
  161 + charT
  162 + charU
  163 + charV
  164 + charW
  165 + charX
  166 + charY
  167 + charZ
  168 + char0
  169 + char1
  170 + char2
  171 + char3
  172 + char4
  173 + char5
  174 +)
  175 +
  176 +var characterMapping = map[byte]byte{
  177 + 'a': charA,
  178 + 'b': charB,
  179 + 'c': charC,
  180 + 'd': charD,
  181 + 'e': charE,
  182 + 'f': charF,
  183 + 'g': charG,
  184 + 'h': charH,
  185 + 'i': charI,
  186 + 'j': charJ,
  187 + 'k': charK,
  188 + 'l': charL,
  189 + 'm': charM,
  190 + 'n': charN,
  191 + 'o': charO,
  192 + 'p': charP,
  193 + 'q': charQ,
  194 + 'r': charR,
  195 + 's': charS,
  196 + 't': charT,
  197 + 'u': charU,
  198 + 'v': charV,
  199 + 'w': charW,
  200 + 'x': charX,
  201 + 'y': charY,
  202 + 'z': charZ,
  203 + '0': char0,
  204 + '1': char1,
  205 + '2': char2,
  206 + '3': char3,
  207 + '4': char4,
  208 + '5': char5,
  209 +}
1 -// Copyright 2014 Richard Lehane. All rights reserved.  
2 -//  
3 -// Licensed under the Apache License, Version 2.0 (the "License");  
4 -// you may not use this file except in compliance with the License.  
5 -// You may obtain a copy of the License at  
6 -//  
7 -// http://www.apache.org/licenses/LICENSE-2.0  
8 -//  
9 -// Unless required by applicable law or agreed to in writing, software  
10 -// distributed under the License is distributed on an "AS IS" BASIS,  
11 -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  
12 -// See the License for the specific language governing permissions and  
13 -// limitations under the License.  
14 -  
15 -package types  
16 -  
17 -import (  
18 - "encoding/binary"  
19 - "strings"  
20 - "unicode/utf16"  
21 -)  
22 -  
23 -func nullTerminated(s string) string {  
24 - return s[:strings.Index(s, "\x00")]  
25 -}  
26 -  
27 -type UnicodeString []uint16  
28 -  
29 -func (s UnicodeString) Type() string {  
30 - return "UnicodeString"  
31 -}  
32 -  
33 -func (s UnicodeString) Length() int {  
34 - return 4 + len(s)*2  
35 -}  
36 -  
37 -func (s UnicodeString) String() string {  
38 - if len(s) == 0 {  
39 - return ""  
40 - }  
41 - return nullTerminated(string(utf16.Decode(s)))  
42 -}  
43 -  
44 -func MakeUnicode(b []byte) (Type, error) {  
45 - if len(b) < 4 {  
46 - return UnicodeString{}, ErrType  
47 - }  
48 - l := int(binary.LittleEndian.Uint32(b[:4]))  
49 - if l == 0 {  
50 - return UnicodeString{}, nil  
51 - }  
52 - if len(b) < l*2+4 {  
53 - return UnicodeString{}, ErrType  
54 - }  
55 - s := make(UnicodeString, l)  
56 - for i := range s {  
57 - start := i*2 + 4  
58 - s[i] = binary.LittleEndian.Uint16(b[start : start+2])  
59 - }  
60 - return s, nil  
61 -}  
62 -  
63 -type CodeString struct {  
64 - id CodePageID  
65 - Chars []byte  
66 -}  
67 -  
68 -func (s *CodeString) SetId(i CodePageID) {  
69 - s.id = i  
70 -}  
71 -  
72 -func (s *CodeString) Encoding() string {  
73 - return CodePageIDs[s.id]  
74 -}  
75 -  
76 -func (s *CodeString) Type() string {  
77 - return "CodeString"  
78 -}  
79 -  
80 -func (s *CodeString) Length() int {  
81 - return 4 + len(s.Chars)  
82 -}  
83 -  
84 -func (s *CodeString) String() string {  
85 - if len(s.Chars) == 0 {  
86 - return ""  
87 - }  
88 - if s.id == 1200 {  
89 - chars := make([]uint16, len(s.Chars)/2)  
90 - for i := range chars {  
91 - chars[i] = binary.LittleEndian.Uint16(s.Chars[i*2 : i*2+2])  
92 - }  
93 - return nullTerminated(string(utf16.Decode(chars)))  
94 - }  
95 - return nullTerminated(string(s.Chars))  
96 -}  
97 -  
98 -func MakeCodeString(b []byte) (Type, error) {  
99 - if len(b) < 4 {  
100 - return &CodeString{}, ErrType  
101 - }  
102 - s := &CodeString{}  
103 - l := int(binary.LittleEndian.Uint32(b[:4]))  
104 - if l == 0 {  
105 - return s, nil  
106 - }  
107 - if len(b) < l+4 {  
108 - return s, ErrType  
109 - }  
110 - s.Chars = make([]byte, l)  
111 - copy(s.Chars, b[4:l+4])  
112 - return s, nil  
113 -}  
114 -  
115 -type CodePageID uint16  
116 -  
117 -var CodePageIDs map[CodePageID]string = map[CodePageID]string{  
118 - 37: "IBM037 - IBM EBCDIC US-Canada",  
119 - 437: "IBM437 - OEM United States",  
120 - 500: "IBM500 - IBM EBCDIC International",  
121 - 708: "ASMO-708 - Arabic (ASMO 708)",  
122 - 709: "Arabic (ASMO-449+, BCON V4)",  
123 - 710: "Arabic - Transparent Arabic",  
124 - 720: "DOS-720 - Arabic (Transparent ASMO); Arabic (DOS)",  
125 - 737: "ibm737 - OEM Greek (formerly 437G); Greek (DOS)",  
126 - 775: "ibm775 - OEM Baltic; Baltic (DOS)",  
127 - 850: "ibm850 - OEM Multilingual Latin 1; Western European (DOS)",  
128 - 852: "ibm852 - OEM Latin 2; Central European (DOS)",  
129 - 855: "IBM855 - OEM Cyrillic (primarily Russian)",  
130 - 857: "ibm857 - OEM Turkish; Turkish (DOS)",  
131 - 858: "IBM00858 - OEM Multilingual Latin 1 + Euro symbol",  
132 - 860: "IBM860 - OEM Portuguese; Portuguese (DOS)",  
133 - 861: "ibm861 - OEM Icelandic; Icelandic (DOS)",  
134 - 862: "DOS-862 - OEM Hebrew; Hebrew (DOS)",  
135 - 863: "IBM863 - OEM French Canadian; French Canadian (DOS)",  
136 - 864: "IBM864 - OEM Arabic; Arabic (864)",  
137 - 865: "IBM865 - OEM Nordic; Nordic (DOS)",  
138 - 866: "cp866 - OEM Russian; Cyrillic (DOS)",  
139 - 869: "ibm869 - OEM Modern Greek; Greek, Modern (DOS)",  
140 - 870: "IBM870 - IBM EBCDIC Multilingual/ROECE (Latin 2); IBM EBCDIC Multilingual Latin 2",  
141 - 874: "windows-874 - ANSI/OEM Thai (ISO 8859-11); Thai (Windows)",  
142 - 875: "cp875 - IBM EBCDIC Greek Modern",  
143 - 932: "shift_jis - ANSI/OEM Japanese; Japanese (Shift-JIS)",  
144 - 936: "gb2312 - ANSI/OEM Simplified Chinese (PRC, Singapore); Chinese Simplified (GB2312)",  
145 - 949: "ks_c_5601-1987 - ANSI/OEM Korean (Unified Hangul Code)",  
146 - 950: "big5 - ANSI/OEM Traditional Chinese (Taiwan; Hong Kong SAR, PRC); Chinese Traditional (Big5)",  
147 - 1026: "IBM1026 - IBM EBCDIC Turkish (Latin 5)",  
148 - 1047: "IBM01047 - BM EBCDIC Latin 1/Open System",  
149 - 1140: "IBM01140 - IBM EBCDIC US-Canada (037 + Euro symbol); IBM EBCDIC (US-Canada-Euro)",  
150 - 1141: "IBM01141 - IBM EBCDIC Germany (20273 + Euro symbol); IBM EBCDIC (Germany-Euro)",  
151 - 1142: "IBM01142 - IBM EBCDIC Denmark-Norway (20277 + Euro symbol); IBM EBCDIC (Denmark-Norway-Euro)",  
152 - 1143: "IBM01143 - IBM EBCDIC Finland-Sweden (20278 + Euro symbol); IBM EBCDIC (Finland-Sweden-Euro)",  
153 - 1144: "IBM01144 - IBM EBCDIC Italy (20280 + Euro symbol); IBM EBCDIC (Italy-Euro)",  
154 - 1145: "IBM01145 - IBM EBCDIC Latin America-Spain (20284 + Euro symbol); IBM EBCDIC (Spain-Euro)",  
155 - 1146: "IBM01146 - IBM EBCDIC United Kingdom (20285 + Euro symbol); IBM EBCDIC (UK-Euro)",  
156 - 1147: "IBM01147 - IBM EBCDIC France (20297 + Euro symbol); IBM EBCDIC (France-Euro)",  
157 - 1148: "IBM01148 - IBM EBCDIC International (500 + Euro symbol); IBM EBCDIC (International-Euro)",  
158 - 1149: "IBM01149 - IBM EBCDIC Icelandic (20871 + Euro symbol); IBM EBCDIC (Icelandic-Euro)",  
159 - 1200: "utf-16 - Unicode UTF-16, little endian byte order (BMP of ISO 10646); available only to managed applications",  
160 - 1201: "unicodeFFFE - Unicode UTF-16, big endian byte order; available only to managed applications",  
161 - 1250: "windows-1250 - ANSI Central European; Central European (Windows)",  
162 - 1251: "windows-1251 - ANSI Cyrillic; Cyrillic (Windows)",  
163 - 1252: "windows-1252 - ANSI Latin 1; Western European (Windows)",  
164 - 1253: "windows-1253 - ANSI Greek; Greek (Windows)",  
165 - 1254: "windows-1254 - ANSI Turkish; Turkish (Windows)",  
166 - 1255: "windows-1255 - ANSI Hebrew; Hebrew (Windows)",  
167 - 1256: "windows-1256 - ANSI Arabic; Arabic (Windows)",  
168 - 1257: "windows-1257 - ANSI Baltic; Baltic (Windows)",  
169 - 1258: "windows-1258 - ANSI/OEM Vietnamese; Vietnamese (Windows)",  
170 - 1361: "Johab - Korean (Johab)",  
171 - 10000: "macintosh - MAC Roman; Western European (Mac)",  
172 - 10001: "x-mac-japanese - Japanese (Mac)",  
173 - 10002: "x-mac-chinesetrad - MAC Traditional Chinese (Big5); Chinese Traditional (Mac)",  
174 - 10003: "x-mac-korean - Korean (Mac)",  
175 - 10004: "x-mac-arabic - Arabic (Mac)",  
176 - 10005: "x-mac-hebrew - Hebrew (Mac)",  
177 - 10006: "x-mac-greek - Greek (Mac)",  
178 - 10007: "x-mac-cyrillic - Cyrillic (Mac)",  
179 - 10008: "x-mac-chinesesimp - MAC Simplified Chinese (GB 2312); Chinese Simplified (Mac)",  
180 - 10010: "x-mac-romanian - Romanian (Mac)",  
181 - 10017: "x-mac-ukrainian - Ukrainian (Mac)",  
182 - 10021: "x-mac-thai - Thai (Mac)",  
183 - 10029: "x-mac-ce - MAC Latin 2; Central European (Mac)",  
184 - 10079: "x-mac-icelandic - Icelandic (Mac)",  
185 - 10081: "x-mac-turkish - Turkish (Mac)",  
186 - 10082: "x-mac-croatian - Croatian (Mac)",  
187 - 12000: "utf-32 - Unicode UTF-32, little endian byte order; available only to managed applications",  
188 - 12001: "utf-32BE - Unicode UTF-32, big endian byte order; available only to managed applications",  
189 - 20000: "x-Chinese_CNS - CNS Taiwan; Chinese Traditional (CNS)",  
190 - 20001: "x-cp20001 - TCA Taiwan",  
191 - 20002: "x_Chinese-Eten - Eten Taiwan; Chinese Traditional (Eten)",  
192 - 20003: "x-cp20003 - IBM5550 Taiwan",  
193 - 20004: "x-cp20004 - TeleText Taiwan",  
194 - 20005: "x-cp20005 - Wang Taiwan",  
195 - 20105: "x-IA5 - IA5 (IRV International Alphabet No. 5, 7-bit); Western European (IA5)",  
196 - 20106: "x-IA5-German - IA5 German (7-bit)",  
197 - 20107: "x-IA5-Swedish - IA5 Swedish (7-bit)",  
198 - 20108: "x-IA5-Norwegian - IA5 Norwegian (7-bit)",  
199 - 20127: "us-ascii - US-ASCII (7-bit)",  
200 - 20261: "x-cp20261 - T.61",  
201 - 20269: "x-cp20269 - ISO 6937 Non-Spacing Accent",  
202 - 20273: "IBM273 - IBM EBCDIC Germany",  
203 - 20277: "IBM277 - IBM EBCDIC Denmark-Norway",  
204 - 20278: "IBM278 - IBM EBCDIC Finland-Sweden",  
205 - 20280: "IBM280 - IBM EBCDIC Italy",  
206 - 20284: "IBM284 - IBM EBCDIC Latin America-Spain",  
207 - 20285: "IBM285 - IBM EBCDIC United Kingdom",  
208 - 20290: "IBM290 - IBM EBCDIC Japanese Katakana Extended",  
209 - 20297: "IBM297 - IBM EBCDIC France",  
210 - 20420: "IBM420 - IBM EBCDIC Arabic",  
211 - 20423: "IBM423 - IBM EBCDIC Greek",  
212 - 20424: "IBM424 - IBM EBCDIC Hebrew",  
213 - 20833: "x-EBCDIC-KoreanExtended - IBM EBCDIC Korean Extended",  
214 - 20838: "IBM-Thai - IBM EBCDIC Thai",  
215 - 20866: "koi8-r - Russian (KOI8-R); Cyrillic (KOI8-R)",  
216 - 20871: "IBM871 - IBM EBCDIC Icelandic",  
217 - 20880: "IBM880 - IBM EBCDIC Cyrillic Russian",  
218 - 20905: "IBM905 - IBM EBCDIC Turkish",  
219 - 20924: "IBM00924 - IBM EBCDIC Latin 1/Open System (1047 + Euro symbol)",  
220 - 20932: "EUC-JP - Japanese (JIS 0208-1990 and 0212-1990)",  
221 - 20936: "x-cp20936 - Simplified Chinese (GB2312); Chinese Simplified (GB2312-80)",  
222 - 20949: "x-cp20949 - Korean Wansung",  
223 - 21025: "cp1025 - IBM EBCDIC Cyrillic Serbian-Bulgarian",  
224 - 21027: "(deprecated)",  
225 - 21866: "koi8-u - Ukrainian (KOI8-U); Cyrillic (KOI8-U)",  
226 - 28591: "iso-8859-1 - ISO 8859-1 Latin 1; Western European (ISO)",  
227 - 28592: "iso-8859-2 - ISO 8859-2 Central European; Central European (ISO)",  
228 - 28593: "iso-8859-3 - ISO 8859-3 Latin 3",  
229 - 28594: "iso-8859-4 - ISO 8859-4 Baltic",  
230 - 28595: "iso-8859-5 - ISO 8859-5 Cyrillic",  
231 - 28596: "iso-8859-6 - ISO 8859-6 Arabic",  
232 - 28597: "iso-8859-7 - ISO 8859-7 Greek",  
233 - 28598: "iso-8859-8 - ISO 8859-8 Hebrew; Hebrew (ISO-Visual)",  
234 - 28599: "iso-8859-9 - ISO 8859-9 Turkish",  
235 - 28603: "iso-8859-13 - ISO 8859-13 Estonian",  
236 - 28605: "iso-8859-15 - ISO 8859-15 Latin 9",  
237 - 29001: "x-Europa - Europa 3",  
238 - 38598: "iso-8859-8-i - ISO 8859-8 Hebrew; Hebrew (ISO-Logical)",  
239 - 50220: "iso-2022-jp - ISO 2022 Japanese with no halfwidth Katakana; Japanese (JIS)",  
240 - 50221: "csISO2022JP - ISO 2022 Japanese with halfwidth Katakana; Japanese (JIS-Allow 1 byte Kana)",  
241 - 50222: "iso-2022-jp - ISO 2022 Japanese JIS X 0201-1989; Japanese (JIS-Allow 1 byte Kana - SO/SI)",  
242 - 50225: "iso-2022-kr - ISO 2022 Korean",  
243 - 50227: "x-cp50227 - ISO 2022 Simplified Chinese; Chinese Simplified (ISO 2022)",  
244 - 50229: "ISO 2022 - Traditional Chinese",  
245 - 50930: "EBCDIC - Japanese (Katakana) Extended",  
246 - 50931: "EBCDIC - US-Canada and Japanese",  
247 - 50933: "EBCDIC - Korean Extended and Korean",  
248 - 50935: "EBCDIC - Simplified Chinese Extended and Simplified Chinese",  
249 - 50936: "EBCDIC - Simplified Chinese",  
250 - 50937: "EBCDIC - US-Canada and Traditional Chinese",  
251 - 50939: "EBCDIC - Japanese (Latin) Extended and Japanese",  
252 - 51932: "euc-jp - EUC Japanese",  
253 - 51936: "EUC-CN - EUC Simplified Chinese; Chinese Simplified (EUC)",  
254 - 51949: "euc-kr - EUC Korean",  
255 - 51950: "EUC - Traditional Chinese",  
256 - 52936: "hz-gb-2312 - HZ-GB2312 Simplified Chinese; Chinese Simplified (HZ)",  
257 - 54936: "GB18030 - Windows XP and later: GB18030 Simplified Chinese (4 byte); Chinese Simplified (GB18030)",  
258 - 57002: "x-iscii-de - ISCII Devanagari",  
259 - 57003: "x-iscii-be - ISCII Bengali",  
260 - 57004: "x-iscii-ta - ISCII Tamil",  
261 - 57005: "x-iscii-te - ISCII Telugu",  
262 - 57006: "x-iscii-as - ISCII Assamese",  
263 - 57007: "x-iscii-or - ISCII Oriya",  
264 - 57008: "x-iscii-ka - ISCII Kannada",  
265 - 57009: "x-iscii-ma - ISCII Malayalam",  
266 - 57010: "x-iscii-gu - ISCII Gujarati",  
267 - 57011: "x-iscii-pa - ISCII Punjabi",  
268 - 65000: "utf-7 - Unicode (UTF-7)",  
269 - 65001: "utf-8 - Unicode (UTF-8)",  
270 -} 1 +// Copyright 2014 Richard Lehane. All rights reserved.
  2 +//
  3 +// Licensed under the Apache License, Version 2.0 (the "License");
  4 +// you may not use this file except in compliance with the License.
  5 +// You may obtain a copy of the License at
  6 +//
  7 +// http://www.apache.org/licenses/LICENSE-2.0
  8 +//
  9 +// Unless required by applicable law or agreed to in writing, software
  10 +// distributed under the License is distributed on an "AS IS" BASIS,
  11 +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12 +// See the License for the specific language governing permissions and
  13 +// limitations under the License.
  14 +
  15 +package types
  16 +
  17 +import (
  18 + "encoding/binary"
  19 + "strings"
  20 + "unicode/utf16"
  21 +)
  22 +
  23 +func nullTerminated(s string) string {
  24 + return s[:strings.Index(s, "\x00")]
  25 +}
  26 +
  27 +type UnicodeString []uint16
  28 +
  29 +func (s UnicodeString) Type() string {
  30 + return "UnicodeString"
  31 +}
  32 +
  33 +func (s UnicodeString) Length() int {
  34 + return 4 + len(s)*2
  35 +}
  36 +
  37 +func (s UnicodeString) String() string {
  38 + if len(s) == 0 {
  39 + return ""
  40 + }
  41 + return nullTerminated(string(utf16.Decode(s)))
  42 +}
  43 +
  44 +func MakeUnicode(b []byte) (Type, error) {
  45 + if len(b) < 4 {
  46 + return UnicodeString{}, ErrType
  47 + }
  48 + l := int(binary.LittleEndian.Uint32(b[:4]))
  49 + if l == 0 {
  50 + return UnicodeString{}, nil
  51 + }
  52 + if len(b) < l*2+4 {
  53 + return UnicodeString{}, ErrType
  54 + }
  55 + s := make(UnicodeString, l)
  56 + for i := range s {
  57 + start := i*2 + 4
  58 + s[i] = binary.LittleEndian.Uint16(b[start : start+2])
  59 + }
  60 + return s, nil
  61 +}
  62 +
  63 +type CodeString struct {
  64 + id CodePageID
  65 + Chars []byte
  66 +}
  67 +
  68 +func (s *CodeString) SetId(i CodePageID) {
  69 + s.id = i
  70 +}
  71 +
  72 +func (s *CodeString) Encoding() string {
  73 + return CodePageIDs[s.id]
  74 +}
  75 +
  76 +func (s *CodeString) Type() string {
  77 + return "CodeString"
  78 +}
  79 +
  80 +func (s *CodeString) Length() int {
  81 + return 4 + len(s.Chars)
  82 +}
  83 +
  84 +func (s *CodeString) String() string {
  85 + if len(s.Chars) == 0 {
  86 + return ""
  87 + }
  88 + if s.id == 1200 {
  89 + chars := make([]uint16, len(s.Chars)/2)
  90 + for i := range chars {
  91 + chars[i] = binary.LittleEndian.Uint16(s.Chars[i*2 : i*2+2])
  92 + }
  93 + return nullTerminated(string(utf16.Decode(chars)))
  94 + }
  95 + return nullTerminated(string(s.Chars))
  96 +}
  97 +
  98 +func MakeCodeString(b []byte) (Type, error) {
  99 + if len(b) < 4 {
  100 + return &CodeString{}, ErrType
  101 + }
  102 + s := &CodeString{}
  103 + l := int(binary.LittleEndian.Uint32(b[:4]))
  104 + if l == 0 {
  105 + return s, nil
  106 + }
  107 + if len(b) < l+4 {
  108 + return s, ErrType
  109 + }
  110 + s.Chars = make([]byte, l)
  111 + copy(s.Chars, b[4:l+4])
  112 + return s, nil
  113 +}
  114 +
  115 +type CodePageID uint16
  116 +
  117 +var CodePageIDs map[CodePageID]string = map[CodePageID]string{
  118 + 37: "IBM037 - IBM EBCDIC US-Canada",
  119 + 437: "IBM437 - OEM United States",
  120 + 500: "IBM500 - IBM EBCDIC International",
  121 + 708: "ASMO-708 - Arabic (ASMO 708)",
  122 + 709: "Arabic (ASMO-449+, BCON V4)",
  123 + 710: "Arabic - Transparent Arabic",
  124 + 720: "DOS-720 - Arabic (Transparent ASMO); Arabic (DOS)",
  125 + 737: "ibm737 - OEM Greek (formerly 437G); Greek (DOS)",
  126 + 775: "ibm775 - OEM Baltic; Baltic (DOS)",
  127 + 850: "ibm850 - OEM Multilingual Latin 1; Western European (DOS)",
  128 + 852: "ibm852 - OEM Latin 2; Central European (DOS)",
  129 + 855: "IBM855 - OEM Cyrillic (primarily Russian)",
  130 + 857: "ibm857 - OEM Turkish; Turkish (DOS)",
  131 + 858: "IBM00858 - OEM Multilingual Latin 1 + Euro symbol",
  132 + 860: "IBM860 - OEM Portuguese; Portuguese (DOS)",
  133 + 861: "ibm861 - OEM Icelandic; Icelandic (DOS)",
  134 + 862: "DOS-862 - OEM Hebrew; Hebrew (DOS)",
  135 + 863: "IBM863 - OEM French Canadian; French Canadian (DOS)",
  136 + 864: "IBM864 - OEM Arabic; Arabic (864)",
  137 + 865: "IBM865 - OEM Nordic; Nordic (DOS)",
  138 + 866: "cp866 - OEM Russian; Cyrillic (DOS)",
  139 + 869: "ibm869 - OEM Modern Greek; Greek, Modern (DOS)",
  140 + 870: "IBM870 - IBM EBCDIC Multilingual/ROECE (Latin 2); IBM EBCDIC Multilingual Latin 2",
  141 + 874: "windows-874 - ANSI/OEM Thai (ISO 8859-11); Thai (Windows)",
  142 + 875: "cp875 - IBM EBCDIC Greek Modern",
  143 + 932: "shift_jis - ANSI/OEM Japanese; Japanese (Shift-JIS)",
  144 + 936: "gb2312 - ANSI/OEM Simplified Chinese (PRC, Singapore); Chinese Simplified (GB2312)",
  145 + 949: "ks_c_5601-1987 - ANSI/OEM Korean (Unified Hangul Code)",
  146 + 950: "big5 - ANSI/OEM Traditional Chinese (Taiwan; Hong Kong SAR, PRC); Chinese Traditional (Big5)",
  147 + 1026: "IBM1026 - IBM EBCDIC Turkish (Latin 5)",
  148 + 1047: "IBM01047 - BM EBCDIC Latin 1/Open System",
  149 + 1140: "IBM01140 - IBM EBCDIC US-Canada (037 + Euro symbol); IBM EBCDIC (US-Canada-Euro)",
  150 + 1141: "IBM01141 - IBM EBCDIC Germany (20273 + Euro symbol); IBM EBCDIC (Germany-Euro)",
  151 + 1142: "IBM01142 - IBM EBCDIC Denmark-Norway (20277 + Euro symbol); IBM EBCDIC (Denmark-Norway-Euro)",
  152 + 1143: "IBM01143 - IBM EBCDIC Finland-Sweden (20278 + Euro symbol); IBM EBCDIC (Finland-Sweden-Euro)",
  153 + 1144: "IBM01144 - IBM EBCDIC Italy (20280 + Euro symbol); IBM EBCDIC (Italy-Euro)",
  154 + 1145: "IBM01145 - IBM EBCDIC Latin America-Spain (20284 + Euro symbol); IBM EBCDIC (Spain-Euro)",
  155 + 1146: "IBM01146 - IBM EBCDIC United Kingdom (20285 + Euro symbol); IBM EBCDIC (UK-Euro)",
  156 + 1147: "IBM01147 - IBM EBCDIC France (20297 + Euro symbol); IBM EBCDIC (France-Euro)",
  157 + 1148: "IBM01148 - IBM EBCDIC International (500 + Euro symbol); IBM EBCDIC (International-Euro)",
  158 + 1149: "IBM01149 - IBM EBCDIC Icelandic (20871 + Euro symbol); IBM EBCDIC (Icelandic-Euro)",
  159 + 1200: "utf-16 - Unicode UTF-16, little endian byte order (BMP of ISO 10646); available only to managed applications",
  160 + 1201: "unicodeFFFE - Unicode UTF-16, big endian byte order; available only to managed applications",
  161 + 1250: "windows-1250 - ANSI Central European; Central European (Windows)",
  162 + 1251: "windows-1251 - ANSI Cyrillic; Cyrillic (Windows)",
  163 + 1252: "windows-1252 - ANSI Latin 1; Western European (Windows)",
  164 + 1253: "windows-1253 - ANSI Greek; Greek (Windows)",
  165 + 1254: "windows-1254 - ANSI Turkish; Turkish (Windows)",
  166 + 1255: "windows-1255 - ANSI Hebrew; Hebrew (Windows)",
  167 + 1256: "windows-1256 - ANSI Arabic; Arabic (Windows)",
  168 + 1257: "windows-1257 - ANSI Baltic; Baltic (Windows)",
  169 + 1258: "windows-1258 - ANSI/OEM Vietnamese; Vietnamese (Windows)",
  170 + 1361: "Johab - Korean (Johab)",
  171 + 10000: "macintosh - MAC Roman; Western European (Mac)",
  172 + 10001: "x-mac-japanese - Japanese (Mac)",
  173 + 10002: "x-mac-chinesetrad - MAC Traditional Chinese (Big5); Chinese Traditional (Mac)",
  174 + 10003: "x-mac-korean - Korean (Mac)",
  175 + 10004: "x-mac-arabic - Arabic (Mac)",
  176 + 10005: "x-mac-hebrew - Hebrew (Mac)",
  177 + 10006: "x-mac-greek - Greek (Mac)",
  178 + 10007: "x-mac-cyrillic - Cyrillic (Mac)",
  179 + 10008: "x-mac-chinesesimp - MAC Simplified Chinese (GB 2312); Chinese Simplified (Mac)",
  180 + 10010: "x-mac-romanian - Romanian (Mac)",
  181 + 10017: "x-mac-ukrainian - Ukrainian (Mac)",
  182 + 10021: "x-mac-thai - Thai (Mac)",
  183 + 10029: "x-mac-ce - MAC Latin 2; Central European (Mac)",
  184 + 10079: "x-mac-icelandic - Icelandic (Mac)",
  185 + 10081: "x-mac-turkish - Turkish (Mac)",
  186 + 10082: "x-mac-croatian - Croatian (Mac)",
  187 + 12000: "utf-32 - Unicode UTF-32, little endian byte order; available only to managed applications",
  188 + 12001: "utf-32BE - Unicode UTF-32, big endian byte order; available only to managed applications",
  189 + 20000: "x-Chinese_CNS - CNS Taiwan; Chinese Traditional (CNS)",
  190 + 20001: "x-cp20001 - TCA Taiwan",
  191 + 20002: "x_Chinese-Eten - Eten Taiwan; Chinese Traditional (Eten)",
  192 + 20003: "x-cp20003 - IBM5550 Taiwan",
  193 + 20004: "x-cp20004 - TeleText Taiwan",
  194 + 20005: "x-cp20005 - Wang Taiwan",
  195 + 20105: "x-IA5 - IA5 (IRV International Alphabet No. 5, 7-bit); Western European (IA5)",
  196 + 20106: "x-IA5-German - IA5 German (7-bit)",
  197 + 20107: "x-IA5-Swedish - IA5 Swedish (7-bit)",
  198 + 20108: "x-IA5-Norwegian - IA5 Norwegian (7-bit)",
  199 + 20127: "us-ascii - US-ASCII (7-bit)",
  200 + 20261: "x-cp20261 - T.61",
  201 + 20269: "x-cp20269 - ISO 6937 Non-Spacing Accent",
  202 + 20273: "IBM273 - IBM EBCDIC Germany",
  203 + 20277: "IBM277 - IBM EBCDIC Denmark-Norway",
  204 + 20278: "IBM278 - IBM EBCDIC Finland-Sweden",
  205 + 20280: "IBM280 - IBM EBCDIC Italy",
  206 + 20284: "IBM284 - IBM EBCDIC Latin America-Spain",
  207 + 20285: "IBM285 - IBM EBCDIC United Kingdom",
  208 + 20290: "IBM290 - IBM EBCDIC Japanese Katakana Extended",
  209 + 20297: "IBM297 - IBM EBCDIC France",
  210 + 20420: "IBM420 - IBM EBCDIC Arabic",
  211 + 20423: "IBM423 - IBM EBCDIC Greek",
  212 + 20424: "IBM424 - IBM EBCDIC Hebrew",
  213 + 20833: "x-EBCDIC-KoreanExtended - IBM EBCDIC Korean Extended",
  214 + 20838: "IBM-Thai - IBM EBCDIC Thai",
  215 + 20866: "koi8-r - Russian (KOI8-R); Cyrillic (KOI8-R)",
  216 + 20871: "IBM871 - IBM EBCDIC Icelandic",
  217 + 20880: "IBM880 - IBM EBCDIC Cyrillic Russian",
  218 + 20905: "IBM905 - IBM EBCDIC Turkish",
  219 + 20924: "IBM00924 - IBM EBCDIC Latin 1/Open System (1047 + Euro symbol)",
  220 + 20932: "EUC-JP - Japanese (JIS 0208-1990 and 0212-1990)",
  221 + 20936: "x-cp20936 - Simplified Chinese (GB2312); Chinese Simplified (GB2312-80)",
  222 + 20949: "x-cp20949 - Korean Wansung",
  223 + 21025: "cp1025 - IBM EBCDIC Cyrillic Serbian-Bulgarian",
  224 + 21027: "(deprecated)",
  225 + 21866: "koi8-u - Ukrainian (KOI8-U); Cyrillic (KOI8-U)",
  226 + 28591: "iso-8859-1 - ISO 8859-1 Latin 1; Western European (ISO)",
  227 + 28592: "iso-8859-2 - ISO 8859-2 Central European; Central European (ISO)",
  228 + 28593: "iso-8859-3 - ISO 8859-3 Latin 3",
  229 + 28594: "iso-8859-4 - ISO 8859-4 Baltic",
  230 + 28595: "iso-8859-5 - ISO 8859-5 Cyrillic",
  231 + 28596: "iso-8859-6 - ISO 8859-6 Arabic",
  232 + 28597: "iso-8859-7 - ISO 8859-7 Greek",
  233 + 28598: "iso-8859-8 - ISO 8859-8 Hebrew; Hebrew (ISO-Visual)",
  234 + 28599: "iso-8859-9 - ISO 8859-9 Turkish",
  235 + 28603: "iso-8859-13 - ISO 8859-13 Estonian",
  236 + 28605: "iso-8859-15 - ISO 8859-15 Latin 9",
  237 + 29001: "x-Europa - Europa 3",
  238 + 38598: "iso-8859-8-i - ISO 8859-8 Hebrew; Hebrew (ISO-Logical)",
  239 + 50220: "iso-2022-jp - ISO 2022 Japanese with no halfwidth Katakana; Japanese (JIS)",
  240 + 50221: "csISO2022JP - ISO 2022 Japanese with halfwidth Katakana; Japanese (JIS-Allow 1 byte Kana)",
  241 + 50222: "iso-2022-jp - ISO 2022 Japanese JIS X 0201-1989; Japanese (JIS-Allow 1 byte Kana - SO/SI)",
  242 + 50225: "iso-2022-kr - ISO 2022 Korean",
  243 + 50227: "x-cp50227 - ISO 2022 Simplified Chinese; Chinese Simplified (ISO 2022)",
  244 + 50229: "ISO 2022 - Traditional Chinese",
  245 + 50930: "EBCDIC - Japanese (Katakana) Extended",
  246 + 50931: "EBCDIC - US-Canada and Japanese",
  247 + 50933: "EBCDIC - Korean Extended and Korean",
  248 + 50935: "EBCDIC - Simplified Chinese Extended and Simplified Chinese",
  249 + 50936: "EBCDIC - Simplified Chinese",
  250 + 50937: "EBCDIC - US-Canada and Traditional Chinese",
  251 + 50939: "EBCDIC - Japanese (Latin) Extended and Japanese",
  252 + 51932: "euc-jp - EUC Japanese",
  253 + 51936: "EUC-CN - EUC Simplified Chinese; Chinese Simplified (EUC)",
  254 + 51949: "euc-kr - EUC Korean",
  255 + 51950: "EUC - Traditional Chinese",
  256 + 52936: "hz-gb-2312 - HZ-GB2312 Simplified Chinese; Chinese Simplified (HZ)",
  257 + 54936: "GB18030 - Windows XP and later: GB18030 Simplified Chinese (4 byte); Chinese Simplified (GB18030)",
  258 + 57002: "x-iscii-de - ISCII Devanagari",
  259 + 57003: "x-iscii-be - ISCII Bengali",
  260 + 57004: "x-iscii-ta - ISCII Tamil",
  261 + 57005: "x-iscii-te - ISCII Telugu",
  262 + 57006: "x-iscii-as - ISCII Assamese",
  263 + 57007: "x-iscii-or - ISCII Oriya",
  264 + 57008: "x-iscii-ka - ISCII Kannada",
  265 + 57009: "x-iscii-ma - ISCII Malayalam",
  266 + 57010: "x-iscii-gu - ISCII Gujarati",
  267 + 57011: "x-iscii-pa - ISCII Punjabi",
  268 + 65000: "utf-7 - Unicode (UTF-7)",
  269 + 65001: "utf-8 - Unicode (UTF-8)",
  270 +}
1 -// Copyright 2014 Richard Lehane. All rights reserved.  
2 -//  
3 -// Licensed under the Apache License, Version 2.0 (the "License");  
4 -// you may not use this file except in compliance with the License.  
5 -// You may obtain a copy of the License at  
6 -//  
7 -// http://www.apache.org/licenses/LICENSE-2.0  
8 -//  
9 -// Unless required by applicable law or agreed to in writing, software  
10 -// distributed under the License is distributed on an "AS IS" BASIS,  
11 -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  
12 -// See the License for the specific language governing permissions and  
13 -// limitations under the License.  
14 -  
15 -package types  
16 -  
17 -import (  
18 - "encoding/binary"  
19 - "errors"  
20 -)  
21 -  
22 -// MakeVariant is defined in vectorArray.go. It calls Evaluate, which refers to the MakeTypes map, so must add at runtime  
23 -func init() { MakeTypes[VT_VARIANT] = MakeVariant }  
24 -  
25 -var (  
26 - ErrType = errors.New("msoleps: error coercing byte stream to type")  
27 - ErrUnknownType = errors.New("msoleps: unknown type error")  
28 -)  
29 -  
30 -type Type interface {  
31 - String() string  
32 - Type() string  
33 - Length() int  
34 -}  
35 -  
36 -const (  
37 - vector uint16 = iota + 1  
38 - array  
39 -)  
40 -  
41 -func Evaluate(b []byte) (Type, error) {  
42 - if len(b) < 4 {  
43 - return I1(0), ErrType  
44 - }  
45 - id := TypeID(binary.LittleEndian.Uint16(b[:2]))  
46 - f, ok := MakeTypes[id]  
47 - if !ok {  
48 - return I1(0), ErrUnknownType  
49 - }  
50 - switch binary.LittleEndian.Uint16(b[2:4]) {  
51 - case vector:  
52 - return MakeVector(f, b[4:])  
53 - case array:  
54 - return MakeArray(f, b[4:])  
55 - }  
56 - return f(b[4:])  
57 -}  
58 -  
59 -type TypeID uint16  
60 -  
61 -const (  
62 - VT_EMPTY TypeID = iota // 0x00  
63 - VT_NULL  
64 - VT_I2  
65 - VT_I4  
66 - VT_R4  
67 - VT_R8  
68 - VT_CY  
69 - VT_DATE  
70 - VT_BSTR  
71 - _  
72 - VT_ERROR  
73 - VT_BOOL  
74 - VT_VARIANT  
75 - _  
76 - VT_DECIMAL  
77 - _  
78 - VT_I1  
79 - VT_U1  
80 - VT_UI2  
81 - VT_UI4  
82 - VT_I8  
83 - VT_UI8  
84 - VT_INT  
85 - VT_UINT //0x17  
86 - _ = iota + 5  
87 - VT_LPSTR //0x1E  
88 - VT_LPWSTR  
89 - VT_FILETIME = iota + 0x25 // 0x40  
90 - VT_BLOB  
91 - VT_STREAM  
92 - VT_STORAGE  
93 - VT_STREAMED_OBJECT  
94 - VT_STORED_OBJECT  
95 - VT_BLOB_OBJECT  
96 - VT_CF  
97 - VT_CLSID  
98 - VT_VERSIONED_STREAM // 0x49  
99 -)  
100 -  
101 -type MakeType func([]byte) (Type, error)  
102 -  
103 -var MakeTypes map[TypeID]MakeType = map[TypeID]MakeType{  
104 - VT_I2: MakeI2,  
105 - VT_I4: MakeI4,  
106 - VT_R4: MakeR4,  
107 - VT_R8: MakeR8,  
108 - VT_CY: MakeCurrency,  
109 - VT_DATE: MakeDate,  
110 - VT_BSTR: MakeCodeString,  
111 - VT_BOOL: MakeBool,  
112 - VT_DECIMAL: MakeDecimal,  
113 - VT_I1: MakeI1,  
114 - VT_U1: MakeUI1,  
115 - VT_UI2: MakeUI2,  
116 - VT_UI4: MakeUI4,  
117 - VT_I8: MakeI8,  
118 - VT_UI8: MakeUI8,  
119 - VT_INT: MakeI4,  
120 - VT_UINT: MakeUI4,  
121 - VT_LPSTR: MakeCodeString,  
122 - VT_LPWSTR: MakeUnicode,  
123 - VT_FILETIME: MakeFileTime,  
124 - VT_CLSID: MakeGuid,  
125 -} 1 +// Copyright 2014 Richard Lehane. All rights reserved.
  2 +//
  3 +// Licensed under the Apache License, Version 2.0 (the "License");
  4 +// you may not use this file except in compliance with the License.
  5 +// You may obtain a copy of the License at
  6 +//
  7 +// http://www.apache.org/licenses/LICENSE-2.0
  8 +//
  9 +// Unless required by applicable law or agreed to in writing, software
  10 +// distributed under the License is distributed on an "AS IS" BASIS,
  11 +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12 +// See the License for the specific language governing permissions and
  13 +// limitations under the License.
  14 +
  15 +package types
  16 +
  17 +import (
  18 + "encoding/binary"
  19 + "errors"
  20 +)
  21 +
  22 +// MakeVariant is defined in vectorArray.go. It calls Evaluate, which refers to the MakeTypes map, so must add at runtime
  23 +func init() { MakeTypes[VT_VARIANT] = MakeVariant }
  24 +
  25 +var (
  26 + ErrType = errors.New("msoleps: error coercing byte stream to type")
  27 + ErrUnknownType = errors.New("msoleps: unknown type error")
  28 +)
  29 +
  30 +type Type interface {
  31 + String() string
  32 + Type() string
  33 + Length() int
  34 +}
  35 +
  36 +const (
  37 + vector uint16 = iota + 1
  38 + array
  39 +)
  40 +
  41 +func Evaluate(b []byte) (Type, error) {
  42 + if len(b) < 4 {
  43 + return I1(0), ErrType
  44 + }
  45 + id := TypeID(binary.LittleEndian.Uint16(b[:2]))
  46 + f, ok := MakeTypes[id]
  47 + if !ok {
  48 + return I1(0), ErrUnknownType
  49 + }
  50 + switch binary.LittleEndian.Uint16(b[2:4]) {
  51 + case vector:
  52 + return MakeVector(f, b[4:])
  53 + case array:
  54 + return MakeArray(f, b[4:])
  55 + }
  56 + return f(b[4:])
  57 +}
  58 +
  59 +type TypeID uint16
  60 +
  61 +const (
  62 + VT_EMPTY TypeID = iota // 0x00
  63 + VT_NULL
  64 + VT_I2
  65 + VT_I4
  66 + VT_R4
  67 + VT_R8
  68 + VT_CY
  69 + VT_DATE
  70 + VT_BSTR
  71 + _
  72 + VT_ERROR
  73 + VT_BOOL
  74 + VT_VARIANT
  75 + _
  76 + VT_DECIMAL
  77 + _
  78 + VT_I1
  79 + VT_U1
  80 + VT_UI2
  81 + VT_UI4
  82 + VT_I8
  83 + VT_UI8
  84 + VT_INT
  85 + VT_UINT //0x17
  86 + _ = iota + 5
  87 + VT_LPSTR //0x1E
  88 + VT_LPWSTR
  89 + VT_FILETIME = iota + 0x25 // 0x40
  90 + VT_BLOB
  91 + VT_STREAM
  92 + VT_STORAGE
  93 + VT_STREAMED_OBJECT
  94 + VT_STORED_OBJECT
  95 + VT_BLOB_OBJECT
  96 + VT_CF
  97 + VT_CLSID
  98 + VT_VERSIONED_STREAM // 0x49
  99 +)
  100 +
  101 +type MakeType func([]byte) (Type, error)
  102 +
  103 +var MakeTypes map[TypeID]MakeType = map[TypeID]MakeType{
  104 + VT_I2: MakeI2,
  105 + VT_I4: MakeI4,
  106 + VT_R4: MakeR4,
  107 + VT_R8: MakeR8,
  108 + VT_CY: MakeCurrency,
  109 + VT_DATE: MakeDate,
  110 + VT_BSTR: MakeCodeString,
  111 + VT_BOOL: MakeBool,
  112 + VT_DECIMAL: MakeDecimal,
  113 + VT_I1: MakeI1,
  114 + VT_U1: MakeUI1,
  115 + VT_UI2: MakeUI2,
  116 + VT_UI4: MakeUI4,
  117 + VT_I8: MakeI8,
  118 + VT_UI8: MakeUI8,
  119 + VT_INT: MakeI4,
  120 + VT_UINT: MakeUI4,
  121 + VT_LPSTR: MakeCodeString,
  122 + VT_LPWSTR: MakeUnicode,
  123 + VT_FILETIME: MakeFileTime,
  124 + VT_CLSID: MakeGuid,
  125 +}
1 -// Copyright 2015 Richard Lehane. All rights reserved.  
2 -//  
3 -// Licensed under the Apache License, Version 2.0 (the "License");  
4 -// you may not use this file except in compliance with the License.  
5 -// You may obtain a copy of the License at  
6 -//  
7 -// http://www.apache.org/licenses/LICENSE-2.0  
8 -//  
9 -// Unless required by applicable law or agreed to in writing, software  
10 -// distributed under the License is distributed on an "AS IS" BASIS,  
11 -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  
12 -// See the License for the specific language governing permissions and  
13 -// limitations under the License.  
14 -  
15 -package types  
16 -  
17 -import (  
18 - "encoding/binary"  
19 -)  
20 -  
21 -type Vector []Type  
22 -  
23 -func (v Vector) String() string {  
24 - return ""  
25 -}  
26 -  
27 -func (v Vector) Type() string {  
28 - if len(v) > 0 {  
29 - return "Vector of " + v[0].Type()  
30 - }  
31 - return "Vector (empty)"  
32 -}  
33 -  
34 -func (v Vector) Length() int {  
35 - ret := 4  
36 - for _, t := range v {  
37 - ret += t.Length()  
38 - }  
39 - return ret  
40 -}  
41 -  
42 -func MakeVector(f MakeType, b []byte) (Type, error) {  
43 - if len(b) < 4 {  
44 - return Vector{}, ErrType  
45 - }  
46 - l := int(binary.LittleEndian.Uint32(b[:4]))  
47 - v := make(Vector, l)  
48 - place := 4  
49 - for i := 0; i < l; i++ {  
50 - t, err := f(b[place:])  
51 - if err != nil {  
52 - return Vector{}, ErrType  
53 - }  
54 - v[i] = t  
55 - place += t.Length()  
56 - }  
57 - return v, nil  
58 -}  
59 -  
60 -type Array [][]Type  
61 -  
62 -func (a Array) String() string {  
63 - return ""  
64 -}  
65 -  
66 -func (a Array) Type() string {  
67 - if len(a) > 0 && len(a[0]) > 0 {  
68 - return "Array of " + a[0][0].Type()  
69 - }  
70 - return "Array (empty)"  
71 -}  
72 -  
73 -func (a Array) Length() int {  
74 - return 0  
75 -}  
76 -  
77 -func MakeArray(f MakeType, b []byte) (Type, error) {  
78 - return Array{}, nil  
79 -}  
80 -  
81 -type Variant struct {  
82 - t Type  
83 -}  
84 -  
85 -func (v Variant) String() string {  
86 - return "Typed Property Value containing " + v.t.String()  
87 -}  
88 -  
89 -func (v Variant) Type() string {  
90 - return "Typed Property Value containing " + v.t.Type()  
91 -}  
92 -  
93 -func (v Variant) Length() int {  
94 - return 4 + v.t.Length()  
95 -}  
96 -  
97 -func MakeVariant(b []byte) (Type, error) {  
98 - t, err := Evaluate(b)  
99 - if err != nil {  
100 - return Variant{}, err  
101 - }  
102 - return Variant{t}, nil  
103 -} 1 +// Copyright 2015 Richard Lehane. All rights reserved.
  2 +//
  3 +// Licensed under the Apache License, Version 2.0 (the "License");
  4 +// you may not use this file except in compliance with the License.
  5 +// You may obtain a copy of the License at
  6 +//
  7 +// http://www.apache.org/licenses/LICENSE-2.0
  8 +//
  9 +// Unless required by applicable law or agreed to in writing, software
  10 +// distributed under the License is distributed on an "AS IS" BASIS,
  11 +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12 +// See the License for the specific language governing permissions and
  13 +// limitations under the License.
  14 +
  15 +package types
  16 +
  17 +import (
  18 + "encoding/binary"
  19 +)
  20 +
  21 +type Vector []Type
  22 +
  23 +func (v Vector) String() string {
  24 + return ""
  25 +}
  26 +
  27 +func (v Vector) Type() string {
  28 + if len(v) > 0 {
  29 + return "Vector of " + v[0].Type()
  30 + }
  31 + return "Vector (empty)"
  32 +}
  33 +
  34 +func (v Vector) Length() int {
  35 + ret := 4
  36 + for _, t := range v {
  37 + ret += t.Length()
  38 + }
  39 + return ret
  40 +}
  41 +
  42 +func MakeVector(f MakeType, b []byte) (Type, error) {
  43 + if len(b) < 4 {
  44 + return Vector{}, ErrType
  45 + }
  46 + l := int(binary.LittleEndian.Uint32(b[:4]))
  47 + v := make(Vector, l)
  48 + place := 4
  49 + for i := 0; i < l; i++ {
  50 + t, err := f(b[place:])
  51 + if err != nil {
  52 + return Vector{}, ErrType
  53 + }
  54 + v[i] = t
  55 + place += t.Length()
  56 + }
  57 + return v, nil
  58 +}
  59 +
  60 +type Array [][]Type
  61 +
  62 +func (a Array) String() string {
  63 + return ""
  64 +}
  65 +
  66 +func (a Array) Type() string {
  67 + if len(a) > 0 && len(a[0]) > 0 {
  68 + return "Array of " + a[0][0].Type()
  69 + }
  70 + return "Array (empty)"
  71 +}
  72 +
  73 +func (a Array) Length() int {
  74 + return 0
  75 +}
  76 +
  77 +func MakeArray(f MakeType, b []byte) (Type, error) {
  78 + return Array{}, nil
  79 +}
  80 +
  81 +type Variant struct {
  82 + t Type
  83 +}
  84 +
  85 +func (v Variant) String() string {
  86 + return "Typed Property Value containing " + v.t.String()
  87 +}
  88 +
  89 +func (v Variant) Type() string {
  90 + return "Typed Property Value containing " + v.t.Type()
  91 +}
  92 +
  93 +func (v Variant) Length() int {
  94 + return 4 + v.t.Length()
  95 +}
  96 +
  97 +func MakeVariant(b []byte) (Type, error) {
  98 + t, err := Evaluate(b)
  99 + if err != nil {
  100 + return Variant{}, err
  101 + }
  102 + return Variant{t}, nil
  103 +}
@@ -3,9 +3,6 @@ @@ -3,9 +3,6 @@
3 github.com/360EntSecGroup-Skylar/excelize/v2 3 github.com/360EntSecGroup-Skylar/excelize/v2
4 # github.com/DataDog/zstd v1.3.6-0.20190409195224-796139022798 4 # github.com/DataDog/zstd v1.3.6-0.20190409195224-796139022798
5 github.com/DataDog/zstd 5 github.com/DataDog/zstd
6 -# github.com/GeeTeam/gt3-golang-sdk v0.0.0-20200116043922-446ca8a507d2  
7 -## explicit  
8 -github.com/GeeTeam/gt3-golang-sdk/geetest  
9 # github.com/Shopify/sarama v1.23.1 6 # github.com/Shopify/sarama v1.23.1
10 ## explicit 7 ## explicit
11 github.com/Shopify/sarama 8 github.com/Shopify/sarama