You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

617 lines
21 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package logic
import (
"encoding/base64"
"errors"
"fmt"
"github.com/golangkit/formatime"
"github.com/jinzhu/gorm"
"github.com/shopspring/decimal"
"github.com/thecodingmachine/gotenberg-go-client/v7"
"gopkg.in/gomail.v2"
"log"
"math/rand"
"path/filepath"
"recook/configs"
"recook/internal/dbc"
"recook/internal/libs/bean"
"recook/internal/libs/docx"
"recook/internal/libs/images"
"recook/internal/model/gys"
"recook/internal/model/vend"
"recook/internal/static_path"
"recook/tools"
"regexp"
"strconv"
"sync"
"time"
)
type EnterpriseInfo struct {
EnterpriseName string `json:"enterpriseName" form:"enterpriseName"` // 企业名称
RegistrationAddress int `json:"registrationAddress" form:"registrationAddress"` // 注册地区
Trade int `json:"trade" form:"trade"` // 贸易类型
CompanyType int `json:"companyType" form:"companyType"` // 公司类型
CompanyTypeInfo string `json:"companyTypeInfo" form:"companyTypeInfo"` // 类型说明
Capital string `json:"capital" form:"capital"` // 注册资本
CapitalDecimal decimal.Decimal
Currency string `json:"currency" form:"currency"` // 货币类型
BusinessStart string `json:"businessStart" form:"businessStart"` // 营业期限开始时间
BusinessStartTime time.Time
BusinessEnd string `json:"businessEnd" form:"businessEnd"` // 营业期限截止时间
BusinessEndTime time.Time
RegistrationProvince string `json:"registrationProvince" form:"registrationProvince"` // 注册地省份
RegistrationCity string `json:"registrationCity" form:"registrationCity"` // 注册地市
RegistrationDistrict string `json:"registrationDistrict" form:"registrationDistrict"` // 注册地区
RegistrationDetailAddress string `json:"registrationDetailAddress" form:"registrationDetailAddress"` // 注册地址
OperationProvince string `json:"operationProvince" form:"operationProvince"` // 经营地省份
OperationCity string `json:"operationCity" form:"operationCity"` // 经营地市
OperationDistrict string `json:"operationDistrict" form:"operationDistrict"` // 经营地区
OperationAddress string `json:"operationAddress" form:"operationAddress"` // 经营地址
EnterpriseCode string `json:"enterpriseCode" form:"enterpriseCode"` // 工商注册号
LicenseUrl string `json:"licenseUrl" form:"licenseUrl"` // 营业执照地址
PayTaxes int `json:"payTaxes" form:"payTaxes"` // 纳税人类型
PaytaxesUrl string `json:"payTaxesUrl" form:"payTaxesUrl"` // 一般纳税人资质
AccountUrl string `json:"accountUrl" form:"accountUrl"` // 银行开户证明
LegalPerson string `json:"legalPerson" form:"legalPerson"` // 法人姓名
LegalPersonCode string `json:"legalPersonCode" form:"legalPersonCode"` // 法人证件号
LegalPersonUrl string `json:"legalPersonUrl" form:"legalPersonUrl"` // 法人证件照
OverseasRegistration string `json:"overseasRegistration" form:"overseasRegistration"` // 注册国家地区
OverseasOperation string `json:"overseasOperation" form:"overseasOperation"` // 经营国家地区
OverseasOperationInfo string `json:"overseasOperationInfo" form:"overseasOperationInfo"` // 详细经营地址
OverseasCode string `json:"overseasCode" form:"overseasCode"` // 商业登记号
OverseasCodeUrl string `json:"overseasCodeUrl" form:"overseasCodeUrl"` // 商业登记注册文件
OverseasAccountUrl string `json:"overseasAccountUrl" form:"overseasAccountUrl"` // 海外银行开户证明
OverseasLegalPerson string `json:"overseasLegalPerson" form:"overseasLegalPerson"` // 法人姓名
OverseasLegalPersonUrl string `json:"overseasLegalPersonUrl" form:"overseasLegalPersonUrl"` // 法人身份证明文件
Sales Sector `json:"sales" form:"sales"` // 业务人员
AfterSales Sector `json:"afterSales" form:"afterSales"` // 售后人员
Account Sector `json:"account" form:"account"` // 对账人员
Brand []BrandItem `json:"brand" form:"brand"` // 品牌信息
}
var (
EnterpriseLogic = &enterprise{}
mu sync.Mutex
date = time.Now().Format("20060102")
noMap = map[int]bool{}
)
type enterprise struct {
}
// @Style 企业信息验证
func (e *enterprise) Verfiy(info *EnterpriseInfo) (err error) {
if info.EnterpriseName == "" {
return errors.New("请填写企业名称")
}
if info.RegistrationAddress < 1 || info.RegistrationAddress > 3 {
return errors.New("注册地非法")
}
if info.RegistrationAddress == 1 {
if info.Trade != 1 && info.Trade != 2 {
return errors.New("贸易类型非法")
}
} else {
if info.Trade != 3 {
return errors.New("贸易类型非法")
}
}
if info.CompanyType < 1 || info.CompanyType > 4 {
return errors.New("公司类型非法")
}
if info.CompanyType == 4 && info.CompanyTypeInfo == "" {
return errors.New("请填写公司类型描述")
}
if info.Capital == "" {
return errors.New("请填写注册资金")
}
info.CapitalDecimal, err = decimal.NewFromString(info.Capital)
if err != nil {
return errors.New("注册资金错误")
}
if info.Currency == "" {
return errors.New("请选择资金币种")
}
if info.BusinessStart == "" || info.BusinessEnd == "" {
return errors.New("请选择营业期限")
}
info.BusinessStartTime, err = time.ParseInLocation("2006-01-02", info.BusinessStart, time.Local)
if err != nil {
return errors.New("请正确填写营业期限")
}
info.BusinessEndTime, err = time.ParseInLocation("2006-01-02", info.BusinessEnd, time.Local)
if err != nil {
return errors.New("请正确填写营业期限")
}
if info.RegistrationAddress == 1 {
if info.RegistrationProvince == "" {
return errors.New("请选择注册省份")
}
if info.RegistrationCity == "" {
return errors.New("请选择注册城市")
}
if info.RegistrationDistrict == "" {
return errors.New("请选择注册区县")
}
if info.OperationProvince == "" {
return errors.New("请选择经营省份")
}
if info.OperationCity == "" {
return errors.New("请选择经营城市")
}
if info.OperationDistrict == "" {
return errors.New("请选择经营区县")
}
if info.OperationAddress == "" {
return errors.New("请填写详细地址")
}
if info.EnterpriseCode == "" {
return errors.New("请填写统一社会信用代码")
}
if info.LicenseUrl == "" {
return errors.New("请上传营业执照副本")
}
if info.PayTaxes < 1 || info.PayTaxes > 2 {
return errors.New("纳税人类型非法")
}
if info.PaytaxesUrl == "" {
return errors.New("请上传纳税人资质")
}
if info.AccountUrl == "" {
return errors.New("请上传银行开户证明")
}
if info.LegalPerson == "" {
return errors.New("请填写法人证明")
}
if !tools.VerifyIdCard(info.LegalPersonCode) {
return errors.New("请正确填写法人身份证号")
}
if info.LegalPersonUrl == "" {
return errors.New("请上传法人身份证")
}
} else {
if info.OverseasRegistration == "" {
return errors.New("请选择注册国家/地区")
}
if info.OverseasOperation == "" {
return errors.New("请选择经营国家/地区")
}
if info.OverseasOperationInfo == "" {
return errors.New("请填写经营地区详细地址")
}
if info.OverseasCode == "" {
return errors.New("请填写商业登记号码")
}
if info.OverseasCodeUrl == "" {
return errors.New("请上传公司登记注册文件")
}
if info.OverseasAccountUrl == "" {
return errors.New("请上传海外银行开户证明")
}
if info.OverseasLegalPerson == "" {
return errors.New("请填写法人姓名")
}
if info.OverseasLegalPersonUrl == "" {
return errors.New("请上传身份证明文件")
}
}
// 联系人验证
if err := SectorLogic.VerfiySector(info.Sales); err != nil {
return err
}
if err := SectorLogic.VerfiySector(info.AfterSales); err != nil {
return err
}
if err := SectorLogic.VerfiySector(info.Account); err != nil {
return err
}
// 品牌信息验证
if err := BrandLogic.VerfiyBrand(&info.Brand); err != nil {
return err
}
return
}
// 企业提交资料
func (e *enterprise) Create(data *vend.GysEnterpriseState, db *gorm.DB) {
db.Create(data)
}
// @Style 更新企业资料
func (e *enterprise) Updates(enterpriseId uint, data *vend.GysEnterpriseState, db *gorm.DB) int64 {
return db.Table(data.TableName()).Where("id = ?", enterpriseId).Updates(&data).RowsAffected
}
// @Style 发送邮件
func (e *enterprise) SendEmail(email string, userId uint) error {
m := gomail.NewMessage()
m.SetHeader("From", configs.Config_Gys_Email_Setting_Mail)
m.SetHeader("To", email)
m.SetHeader("Subject", "瑞库客平台消息通知--【审核通知】!")
state := vend.GysEnterpriseState{}
dbc.DB.First(&state, "user_id = ?", userId)
gysUser := vend.GysUsers{}
dbc.DB.First(&gysUser, "id = ?", userId)
if state.ID <= 0 {
log.Println("sendMailError: 未查询到供应商信息 user_id:", userId, ";email:", email)
return nil
}
m.SetBody("text/html", fmt.Sprintf(`尊敬的供应商 %s
<br/><br/>
您好!
<br/><br/>
恭喜您通过瑞库客供应商资质审核请下载附件签署纸质协议盖章后请寄送至浙江省宁波市高新区菁华路108号德邦大厦4楼收件人瑞库客招商部 400-889-4489
<br/><br/>
瑞库客供应商后台地址:<a href="%s">%s</a><br/>
账号:%s<br/>
密码:%s<br/>
系统邮件,请勿回复!`, state.EnterpriseName, configs.GYS_Login_Url, configs.GYS_Login_Url, gysUser.Username, gysUser.Password))
doc, err := e.GetContractDoc(state)
if err != nil {
log.Println("sendMailError: err:", err, " ;user_id:", userId, ";email:", email)
return err
}
c := &gotenberg.Client{Hostname: configs.Config_Gotenberg}
docx, err := gotenberg.NewDocumentFromPath("contract.docx", doc)
if err != nil {
return err
}
req := gotenberg.NewOfficeRequest(docx)
req.WaitTimeout(30)
filename := static_path.Dir.Root + "/contract/pdf/瑞库客平台合作协议_" + state.ContractNo + ".pdf"
if err := c.Store(req, filename); err != nil {
return err
}
m.Attach(filename, gomail.Rename("=?utf-8?B?"+base64.StdEncoding.EncodeToString([]byte("瑞库客平台合作协议_"+state.ContractNo+".pdf"))+"?="))
d := gomail.NewDialer(configs.Config_Gys_Email_Setting_Smtp, configs.Config_Gys_Email_Setting_Port, configs.Config_Gys_Email_Setting_User, configs.Config_Gys_Email_Setting_Pass)
if err := d.DialAndSend(m); err != nil {
return err
}
return nil
}
type ArgsYes struct {
PayTaxes int `json:"payTaxes" form:"payTaxes"`
EnterpriseId uint `json:"enterpriseId" form:"enterpriseId"`
ContractStart string `json:"contractStart" form:"contractStart"`
ContractStartTime formatime.Second
ContraceEnd string `json:"contraceEnd" form:"contraceEnd"`
ContraceEndTime formatime.Second
Deposit float64 `json:"deposit" form:"deposit"`
Period int `json:"period" form:"period"`
PaytaxesUrl string `json:"paytaxesUrl" form:"paytaxesUrl"`
}
// @Style 审核成功验证
func (e *enterprise) Verified(data *ArgsYes) error {
if data.PayTaxes > 2 {
return errors.New("一般纳税人错误")
}
if data.PayTaxes < 1 {
return errors.New("一般纳税人错误")
}
if data.EnterpriseId <= 0 {
return errors.New("参数错误")
}
if data.ContractStart == "" {
return errors.New("合同开始时间不能为空")
}
contractStart, err := time.ParseInLocation("2006-01-02", data.ContractStart, time.Local)
if err != nil {
return err
}
data.ContractStartTime = formatime.NewSecondFrom(contractStart)
contractEnd, err := time.ParseInLocation("2006-01-02", data.ContraceEnd, time.Local)
if err != nil {
return err
}
data.ContraceEndTime = formatime.NewSecondFrom(contractEnd)
if data.Deposit < 0 {
return errors.New("保证金错误")
}
if data.Period <= 0 {
return errors.New("账期错误")
}
if data.PayTaxes == 1 {
if data.PaytaxesUrl == "" {
return errors.New("请上传纳税人资格证")
}
}
return nil
}
// @Style 合同初始化
func (*enterprise) ContractInit(contractNo string, companyName, taxNumber, address, bankName, bankCode string, source gys.GysSource) error {
contractPath := filepath.Join(static_path.Dir.Root, static_path.Dir.Photo, "/contract")
font := "./credentials/font/simsun.ttc"
filename := tools.MD5(contractNo+"-contract-01.jpg") + ".jpg"
err := images.WaterMark(contractPath+"/contract-01.jpg", font, contractPath+"/"+filename, []images.ContentItem{
{
Content: contractNo,
X: 622,
Y: 125,
}, {
Content: source.Name,
X: 330,
Y: 710,
FontSizt: 16,
}, {
Content: source.OperationAddress,
X: 235,
Y: 734,
FontSizt: 16,
}, {
Content: companyName,
X: 330,
Y: 780,
FontSizt: 16,
}, {
Content: address,
X: 235,
Y: 802,
FontSizt: 16,
},
}, []images.FileItem{})
if err != nil {
return err
}
filename = tools.MD5(contractNo+"-contract-03.jpg") + ".jpg"
err = images.WaterMark(contractPath+"/contract-03.jpg", font, contractPath+"/"+filename, []images.ContentItem{
{
Content: companyName,
X: 215,
Y: 225,
}, {
Content: taxNumber,
X: 242,
Y: 256,
}, {
Content: address,
X: 184,
Y: 288,
}, {
Content: bankName,
X: 200,
Y: 318,
}, {
Content: bankCode,
X: 184,
Y: 350,
},
}, []images.FileItem{})
if err != nil {
return err
}
filename = tools.MD5(contractNo+"-contract-04.jpg") + ".jpg"
err = images.WaterMark(contractPath+"/contract-04.jpg", font, contractPath+"/"+filename, []images.ContentItem{
{
Content: companyName,
X: 215,
Y: 225,
}, {
Content: taxNumber,
X: 242,
Y: 256,
}, {
Content: address,
X: 184,
Y: 288,
}, {
Content: bankName,
X: 200,
Y: 318,
}, {
Content: bankCode,
X: 184,
Y: 350,
}, {
Content: source.Name,
X: 215,
Y: 907,
}, {
Content: source.TaxNumber,
X: 242,
Y: 938,
}, {
Content: source.Address,
X: 184,
Y: 970,
}, {
Content: source.BankName,
X: 200,
Y: 1000,
}, {
Content: source.BankCode,
X: 184,
Y: 1032,
},
}, []images.FileItem{})
if err != nil {
return err
}
filename = tools.MD5(contractNo+"-contract-05.jpg") + ".jpg"
err = images.WaterMark(contractPath+"/contract-05.jpg", font, contractPath+"/"+filename, []images.ContentItem{
{
Content: companyName,
X: 215,
Y: 225,
}, {
Content: taxNumber,
X: 242,
Y: 256,
}, {
Content: address,
X: 184,
Y: 288,
}, {
Content: bankName,
X: 200,
Y: 318,
}, {
Content: bankCode,
X: 184,
Y: 350,
},
}, []images.FileItem{})
if err != nil {
return err
}
return nil
}
// @Style 获取合同编号
func (e *enterprise) GetContractNo() (no string, err error) {
nowDate := time.Now().Format("20060102")
mu.Lock()
defer mu.Unlock()
if date != nowDate {
date = nowDate
noMap = map[int]bool{}
} else {
if len(noMap) >= 10000 {
return "", errors.New("合同编号生成失败")
}
}
for {
contractNo := rand.Intn(9998) + 1
if !noMap[contractNo] {
noMap[contractNo] = true
return fmt.Sprintf("%s%.4d", date, contractNo), err
}
}
}
// @Style 合同
func (e *enterprise) GetContractDoc(state vend.GysEnterpriseState) (string, error) {
gysSource := &gys.GysSource{}
dbc.DB.First(&gysSource, "id = ?", state.Source)
r, err := docx.ReadDocxFile("./credentials/contract/contract.docx")
if err != nil {
return "", err
}
defer r.Close()
docx1 := r.Editable()
now := time.Now()
docx1.Replace("Year", now.Format("2006"), -1)
docx1.Replace("Month", now.Format("01"), -1)
docx1.Replace("Day", now.Format("02"), -1)
docx1.Replace("SourceName", gysSource.Name, -1)
docx1.Replace("SourceOperationAddress", gysSource.OperationAddress, -1)
docx1.Replace("SourceTaxNumber", gysSource.TaxNumber, -1)
docx1.Replace("SourceAddress", gysSource.Address, -1)
docx1.Replace("SourceBankName", gysSource.BankName, -1)
docx1.Replace("SourceBankCode", gysSource.BankCode, -1)
docx1.Replace("ContractNo", state.ContractNo, -1)
docx1.Replace("EnterpriseName", state.EnterpriseName, -1)
docx1.Replace("OperationAddress", state.OperationAddress, -1)
docx1.Replace("Address", state.RegistrationDetailAddress, -1)
docx1.Replace("UpDeposit", e.ConvertNumToCny(float64(state.Deposit.IntPart())), -1)
docx1.Replace("Deposit", state.Deposit.String(), -1)
docx1.Replace("TaxNumber", state.TaxNumber, -1)
docx1.Replace("BankName", state.BankName, -1)
docx1.Replace("BankCode", state.BankCode, -1)
if state.Period == 1 {
docx1.Replace("PeriodText", "乙方以甲方后台出具的对账单为结算依据,一个月四次对账期,每月 1 日-7 日8 日核对8 日-14 日15 日核对; 15 日-21 日22 日核对22 日-30 日(或 31 日次月1日核对遇节假日顺延", -1)
} else {
docx1.Replace("PeriodText", "乙方以甲方后台出具的对账单为结算依据,一个月两次对账期, 每月 1 日-15 日16 日核对16 日-30 日(或 31 日),次月 1 日核对,遇节假日顺延", -1)
}
docx1.Replace("ContractStart", state.ContractStart.Time.Format(" 2006 年 01 月 02 日"), -1)
docx1.Replace("ContractEnd", state.ContractEnd.Time.Format(" 2006 年 01 月 02 日"), -1)
filename := static_path.Dir.Root + "/contract/瑞库客平台合作协议_" + state.ContractNo + ".docx"
err = docx1.WriteToFile(filename)
if err != nil {
return "", err
}
return filename, nil
}
// @Style 人民币转大写
func (e *enterprise) ConvertNumToCny(num float64) string {
if num == 0 {
return "零"
}
strnum := strconv.FormatFloat(num*100, 'f', 0, 64)
sliceUnit := []string{"仟", "佰", "拾", "亿", "仟", "佰", "拾", "万", "仟", "佰", "拾", "元", "角", "分"}
s := sliceUnit[len(sliceUnit)-len(strnum) : len(sliceUnit)]
upperDigitUnit := map[string]string{"0": "零", "1": "壹", "2": "贰", "3": "叁", "4": "肆", "5": "伍", "6": "陆", "7": "柒", "8": "捌", "9": "玖"}
str := ""
for k, v := range strnum[:] {
str = str + upperDigitUnit[string(v)] + s[k]
}
reg, err := regexp.Compile(`零角零分$`)
str = reg.ReplaceAllString(str, "")
reg, err = regexp.Compile(`零角`)
str = reg.ReplaceAllString(str, "零")
reg, err = regexp.Compile(`零分$`)
str = reg.ReplaceAllString(str, "")
reg, err = regexp.Compile(`零[仟佰拾]`)
str = reg.ReplaceAllString(str, "零")
reg, err = regexp.Compile(`{2,}`)
str = reg.ReplaceAllString(str, "零")
reg, err = regexp.Compile(`零亿`)
str = reg.ReplaceAllString(str, "亿")
reg, err = regexp.Compile(`零万`)
str = reg.ReplaceAllString(str, "万")
reg, err = regexp.Compile(`零*元`)
str = reg.ReplaceAllString(str, "")
reg, err = regexp.Compile(`亿万`)
str = reg.ReplaceAllString(str, "亿")
reg, err = regexp.Compile(`零元`)
str = reg.ReplaceAllString(str, "零")
if err != nil {
}
return str
}
func (e *enterprise) Lists(status int, enterpriseName, contractNo string, source uint, comitTimeStart, comitTimeEnd, adminDateStart, adminDateEnd string, page bean.Page) (total int, lists []vend.GysEnterpriseState) {
lists = []vend.GysEnterpriseState{}
// 状态
whereStr := "company_id > 0 and state = ? "
whereValue := []interface{}{status}
// 企业名称
if enterpriseName != "" {
whereStr += "and enterprise_name like ? "
whereValue = append(whereValue, "%"+enterpriseName+"%")
}
// 合同编号
if contractNo != "" {
whereStr += "and contract_no = ? "
whereValue = append(whereValue, contractNo)
}
// 运营方
if source > 0 {
whereStr += "and source = ? "
whereValue = append(whereValue, source)
}
// 申请时间
if comitTimeStart != "" && comitTimeEnd != "" {
whereStr += "and comit_time between ? and ? "
whereValue = append(whereValue, comitTimeStart+" 00:00:00", comitTimeEnd+" 23:59:59")
}
// 审核时间
if adminDateStart != "" && adminDateEnd != "" {
whereStr += "and admin_date between ? and ? "
whereValue = append(whereValue, adminDateStart+" 00:00:00", adminDateEnd+" 23:59:59")
}
start := page.GetStart()
dbc.DB.Model(&vend.GysEnterpriseState{}).Where(whereStr, whereValue...).Count(&total)
if total > start {
dbc.DB.Model(&vend.GysEnterpriseState{}).Where(whereStr, whereValue...).Offset(start).Limit(page.GetLimit()).Find(&lists)
}
return
}