Compare commits

...

44 Commits

Author SHA1 Message Date
58418effd3 1、产品库存汇总(按门店)总金额四舍五入。 2024-09-20 17:05:43 +08:00
51baf26dcc 1、产品库存汇总(按门店)总金额四舍五入; 2024-09-20 15:31:04 +08:00
ca63f38c48 1、优化零售退货单反审核失败问题;
2、新建零售退货订单拆分非串码商品时,同步拆分退货数量和退货金额字段;零售列表合并非串码商品时,同步合并退货数量和退货金额字段;修复后解决商品零售毛利汇总退货单多个相同非串码商品退货金额统计不准确的问题;
2024-09-20 14:24:33 +08:00
a9ab3b4d72 1、优化对串码商品的判断,imei_type为2/3都是串码商品; 2024-09-20 11:14:16 +08:00
07544bcc1c 1、采购订单入库相关金额恢复2位小数;相同商品除不尽的情况通过新建多条数据来处理; 2024-09-20 10:58:13 +08:00
2ff86339b1 1、修复串码商品(手动添加)零售退货订单审核失败的缺陷; 2024-09-19 23:21:16 +08:00
d6472c05b4 1、修改库存调拨入库编号生成规则;
2、采购入库的计划单价和执行单价保留3位小数,方便采购处理除不尽的情况;
3、修改商品资料前端入参分页错误时,接口报错的缺陷;
2024-09-19 20:19:53 +08:00
2a4f28f9a8 1、修改库存调拨收货时,库存列表数据重复或者加锁的问题; 2024-09-11 17:32:56 +08:00
d95814ad95 1、零售订单新建和列表接口增加对浮点型数据的四舍五入; 2024-09-11 14:34:01 +08:00
16e12f85cb 1、创建零售退货订单时,单个商品退货金额以入参为准;
2、优化库存导入接口,尝试解决库存列表数据重复的问题;
2024-09-10 20:15:26 +08:00
75553fa63d 1、零售明细退货订单支付方式汇总扣除退货金额; 2024-09-09 16:34:24 +08:00
606d1e513e 1、修改库存详情采购成本合计、员工成本合计字段类型,返回小数部分;
2、商品零售毛利汇总页,员工毛利添加四舍五入;
3、查询采购报表(按商品)页"已终止"的订单不返回未执行金额和数量,汇总数据增加四舍五入;
2024-09-09 15:32:50 +08:00
315e22a488 1、优化零售订单小票打印时间,以实际支付时间为准; 2024-09-06 10:33:25 +08:00
502a67429e 1、修复库存调拨编辑订单添加商品报错的缺陷;
2、修改采购订单反审核报错的缺陷;
2024-09-06 09:57:30 +08:00
5d99ba9e64 1、解决采购需求页面库存数量统计不准确的问题,初始值由0改成1;
2、导出库存详excel时增加"库存数量"列,数量默认为1,方便采购进行excel数据透视;
2024-09-02 17:43:34 +08:00
c8cedfb72e 1.修改排序规则,零售订单根据制单时间降序排列,零售明细根据审核时间降序排列;
2.修复编辑零售订单后created_at时间为空的缺陷;
2024-08-22 10:45:04 +08:00
8cda813a09 1.根据财务要求配置不同门店的收款账户; 2024-08-21 14:13:54 +08:00
e45772ab7c 1.修复编辑商品资料后更新创建时间为空的缺陷;
2.修复进销存报表通过分类、名称查询报错的问题;
3.零售订单开单优化,允许非会员手机号为空的情况;
4.修复库存调拨、库存变动、采购订单、供应商等功能编辑时部分数据不能置为空,且创建时间会更新为空的问题;
2024-08-16 17:42:37 +08:00
2033896d43 1.优化进销存报表,新增系统入库字段; 2024-08-15 11:50:53 +08:00
4537477eff 1.零售管理基础资料增加图片上传功能;
2.采购需求和采购需求提报页面增加商品图片展示列;
2024-08-14 09:52:38 +08:00
39589bfe0f 1.财务统计页增加excel导出功能; 2024-08-12 16:05:56 +08:00
c7216aa035 1.修复采购需求提报先选分类然后分页没效果的缺陷; 2024-08-12 11:29:23 +08:00
c7ab2b1957 1.修复进销存报表时间段查询不准确的问题; 2024-08-09 19:23:21 +08:00
0c3fc88c8d 1.修复采购报表(按商品)查询商品数量不准确的问题; 2024-08-01 16:11:40 +08:00
c64de0727b 1.修复供应商采购汇总部分金额没有四舍五入的缺陷; 2024-08-01 10:22:30 +08:00
ce6708942a 1.修复采购需求打开隐藏无采购需求商品按钮后查询无反应的缺陷; 2024-07-30 15:14:20 +08:00
8efca2321e 1.修复供应商采购汇总处的缺陷; 2024-07-30 11:11:03 +08:00
7d0a36dff1 1.修复店员识别码搜索缺陷; 2024-07-30 10:29:07 +08:00
e9ac976f48 1.优化进销存报表查询时间改成created_at字段;
2.零售订单审核和更新增加updated_at字段;
3.修复会员过期提醒sql报错问题;
4.修复短信使用量统计错误的缺陷;
2024-07-25 20:02:35 +08:00
16c6f1671c 1.修复系统用户编辑后密码无法登录的缺陷;
2.修复系统用户编辑时错误提示;
2024-07-24 16:27:38 +08:00
b50abd884b 1.修复修改GetUserById导致报错问题,新增GetSysUserById; 2024-07-24 15:04:40 +08:00
7e21a88722 1.修复系统用户导出excel数据不全的缺陷; 2024-07-24 14:40:54 +08:00
8f1e1b15d0 1.修复系统用户编辑时会把密码置为空的缺陷; 2024-07-24 14:32:03 +08:00
499959fa41 1.优化商品资料excel导出功能; 2024-07-23 18:40:52 +08:00
b817b7fd40 1.优化采购需求导出全部数据时偶尔崩溃的问题; 2024-07-23 17:14:19 +08:00
5ed025bb22 1.优化采购需求excel导出格式,数据为0的单元格置空; 2024-07-23 10:51:11 +08:00
596fd1dc44 1.修复采购需求的缺陷;
2.优惠券Coupon增加规则字段rule;
2024-07-23 10:28:53 +08:00
1212d9dd1e 1.优化excel导出,门店经营、商品零售毛利汇总、零售明细等页面支持敏感字段配置隐藏或展示; 2024-07-22 10:39:22 +08:00
6fb8697585 1.修改进销存报表筛选时间后报错问题;
2.修复查询采购报表(按商品)已执行金额错误问题;
3.采购明细导出excel支持字段配置;
4.系统用户支持配置店员兑换码和导出excel表格;
2024-07-19 10:06:02 +08:00
973b77d5e9 1.修复采购报表(按单)汇总金额和数量只是当前页的问题; 2024-07-17 12:12:12 +08:00
6c65d3940b 1.解决产品入库,库存增加时串码可以重复的缺陷,增加判断;
2.修复库存调拨反审核失败的缺陷,在待发货,待收货状态反审核查找库存时门店id需使用调出门店id;
2024-07-17 10:56:16 +08:00
b7472787c0 1.优化进销存报表接口查询慢的问题; 2024-07-16 18:30:46 +08:00
87c55b0cda 1.修复零售订单编辑添加新增商品时没有订单id的缺陷;
2.添加迪为的商户信息文件;
2024-07-15 10:34:13 +08:00
6b747385a5 1.修复库存调拨缺陷,调入门店的商品可能之前没有,需要新增记录;
2.修复库存变动缺陷,查找库存可用id时主键不一致;
2024-07-12 19:38:41 +08:00
39 changed files with 4972 additions and 1530 deletions

1
.gitignore vendored
View File

@ -1,4 +1,5 @@
.idea
./logs/*
./temp/*
dev-go-admin
main.exe

View File

@ -100,6 +100,7 @@ func CommodityCreate(c *gin.Context) {
MemberDiscount: memberDiscountFloat,
Origin: req.Origin,
Remark: req.Remark,
Img: req.Img,
}
err = commodity.SetErpCategory()
if err != nil {
@ -263,6 +264,7 @@ func CommodityEdit(c *gin.Context) {
MemberDiscount: memberDiscountFloat,
Origin: req.Origin,
Remark: req.Remark,
Img: req.Img,
}
commodity.ID = req.Id
err = commodity.SetErpCategory()
@ -328,7 +330,7 @@ func CommodityEdit(c *gin.Context) {
}
begin := orm.Eloquent.Begin()
err = begin.Save(commodity).Error
err = begin.Omit("created_at").Save(commodity).Error
if err != nil {
logger.Error("create commodity err:", logger.Field("err", err))
app.Error(c, http.StatusInternalServerError, err, "操作失败")

View File

@ -115,7 +115,16 @@ func SupplierUpdate(c *gin.Context) {
app.Error(c, http.StatusBadRequest, errors.New("para err"), "参数错误")
return
}
var supplierInfo models.Supplier
err := orm.Eloquent.Model(models.Supplier{}).Where("id", req.Id).Find(&supplierInfo).Error
if err != nil || err == models.RecordNotFound {
app.Error(c, http.StatusBadRequest, errors.New("para err"), "参数错误")
return
}
supplier := &models.Supplier{
Number: supplierInfo.Number,
Name: req.Name,
Contact: req.Contact,
Tel: req.Tel,
@ -131,6 +140,7 @@ func SupplierUpdate(c *gin.Context) {
City: req.City,
Area: req.Area,
AccountHolder: req.AccountHolder,
CooperativeBusinessId: middleware.GetCooperativeBusinessId(c),
}
if len(req.BankList) != 0 {
@ -144,7 +154,7 @@ func SupplierUpdate(c *gin.Context) {
supplier.BankData = ""
}
err := orm.Eloquent.Where("id", req.Id).Updates(supplier).Error
err = orm.Eloquent.Where("id", req.Id).Omit("created_at").Save(&supplier).Error
if err != nil {
logger.Error("update supplier err :", logger.Field("err", err), logger.Field("s", supplier))
app.Error(c, http.StatusInternalServerError, err, "更新失败")

View File

@ -35,6 +35,13 @@ func ErpOrderCreate(c *gin.Context) {
return
}
tools.RoundFloatFields(req)
// 如果用户是会员,手机号不能为空
if req.MemberType == model.ErpOrderMemberTypeMember && req.Tel == "" {
app.Error(c, http.StatusBadRequest, errors.New("参数错误:缺少会员手机号"), "参数错误:缺少会员手机号")
}
err = model.CreateErpOrder(req, c)
if err != nil {
logger.Error("CreateErpOrder err:", logger.Field("err", err))
@ -68,6 +75,11 @@ func ErpOrderEdit(c *gin.Context) {
return
}
// 如果用户是会员,手机号不能为空
if req.MemberType == model.ErpOrderMemberTypeMember && req.Tel == "" {
app.Error(c, http.StatusBadRequest, errors.New("参数错误:缺少会员手机号"), "参数错误:缺少会员手机号")
}
err = model.EditErpOrder(req, c)
if err != nil {
logger.Error("EditErpOrder err:", logger.Field("err", err))
@ -195,6 +207,7 @@ func ErpOrderAudit(c *gin.Context) {
}
var checkReq model.ErpOrderCreateReq
checkReq.StoreId = erpOrder.StoreId
checkReq.ErpOrderCommodities = commodity
err = model.CheckOrderCommodityStock(&checkReq)
if err != nil {
@ -234,6 +247,7 @@ func ErpOrderAudit(c *gin.Context) {
"audit_time": time.Now(),
"auditor_name": sysUser.NickName,
"auditor_id": sysUser.UserId,
"updated_at": time.Now(),
}).Error
if err != nil {
begin.Rollback()

View File

@ -249,6 +249,14 @@ func ExpressNoList(c *gin.Context) {
//app.OK(c, nil, "")
}
// FundRecordList 查询财务统计列表
// @Summary 查询财务统计列表
// @Tags 财务管理
// @Produce json
// @Accept json
// @Param request body models.FundRecordListReq true "查询财务统计列表模型"
// @Success 200 {object} models.FundRecordListResp
// @Router /api/v1/order/fund_record/list [post]
func FundRecordList(c *gin.Context) {
req := &models.FundRecordListReq{}
if c.ShouldBindJSON(req) != nil {
@ -257,18 +265,19 @@ func FundRecordList(c *gin.Context) {
return
}
list, count, err := req.List()
list, count, exportUrl, err := req.List()
if err != nil {
logger.Errorf("err:", logger.Field("err", err))
app.Error(c, http.StatusInternalServerError, err, "查询失败")
return
}
ret := map[string]interface{}{
"total": count,
"list": list,
"pageIndex": req.Page,
"pageSize": req.PageSize,
ret := models.FundRecordListResp{
Total: count,
List: list,
PageIndex: req.Page,
PageSize: req.PageSize,
ExportUrl: exportUrl,
}
app.OK(c, ret, "")
}

View File

@ -87,8 +87,30 @@ const (
TimeFormat = "2006-01-02 15:04:05"
clientIp = "39.108.188.218" // 小程序服务器
clientIpDev = "112.33.14.191" // 移动云服务器
HmPayMerchantIdDeovo = "664403000021193"
HmPubKeyDeovo = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCDA4g8VFWIxEbOzxYC8ZIOgaOsLWK4Y5k9D8GwJ1Gige79LbTxbe3PH12KMc59DpCR1PnIDwlYWjIE7mZZAHgImXs0pSFihvlNS9srWk2uPlEXXQjjIZ3mnPoXtNhU0x5cYdkB8jtijcYMSGwKmdrIvpvPX3MrDKOX6dJ1T4ll+QIDAQAB"
// HmPayMerchantIdSwitch 任天堂项目-对私账户(密钥20240701203620)
HmPayMerchantIdSwitch = "664403000021193"
HmPubKeySwitch = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCDA4g8VFWIxEbOzxYC8ZIOgaOsLWK4Y5k9D8GwJ1Gige79LbTxbe3PH12KMc59DpCR1PnIDwlYWjIE7mZZAHgImXs0pSFihvlNS9srWk2uPlEXXQjjIZ3mnPoXtNhU0x5cYdkB8jtijcYMSGwKmdrIvpvPX3MrDKOX6dJ1T4ll+QIDAQAB"
HmPubKeySwitchFp = "./config/hm_pay/switch_private_key.pem"
TestHmPubKeySwitchFp = "/Users/max/Documents/code/deovo/mh_goadmin_server/config/hm_pay/switch_private_key.pem"
// HmPayMerchantIdSwitchPub 任天堂项目-对公账户(密钥20240819161949)
HmPayMerchantIdSwitchPub = "664403000021225"
HmPubKeySwitchPub = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCBsfp+BrCGD39noWjW4z0VvvsFCWzU8vhAWlwGo/dkPxgQLXBNaTApUpavbQ6m/S0x5hQjcKwQ3UrJLDV70SAqPuO3QP0iagMKo2M6ROCO69L06In4gbqTTtTOb/1xpkbsVHd/9Wy/fyxreg1LY+MLzysH+OHAjjjiAYVL4e765QIDAQAB"
HmPubKeySwitchPubFp = "./config/hm_pay/switch_pub_private_key.pem"
TestHmPubKeySwitchPubFp = "/Users/max/Documents/code/deovo/mh_goadmin_server/config/hm_pay/switch_pub_private_key.pem"
// HmPayMerchantIdJBL 哈曼项目-对私账户(密钥20240820145322)
HmPayMerchantIdJBL = "664403000021330"
HmPubKeyJBL = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCBhzboiNtCxDF3QXdPGx5aS2UjXSqq1p2JsIe+PhCWLdaNHoQxzTS0s41KuWbSDpSmtUhutBJZ1QBy+84iLmLKJ5E7UfUIGbrI309hJLQxQey655wWYBtkOVpq6aozjjnnjQjDbYG1WuFmLA03mzQ51VLr4555ioo70hredjLaVQIDAQAB"
HmPubKeyJBLFp = "./config/hm_pay/jbl_private_key.pem"
TestHmPubKeyJBLFp = "/Users/max/Documents/code/deovo/mh_goadmin_server/config/hm_pay/jbl_private_key.pem"
// HmPayMerchantIdJBLPub 哈曼项目-对公账户
HmPayMerchantIdJBLPub = "664403000021340"
HmPubKeyJBLPub = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDIjqYgPO1kj3NI0WEfOCnKYUHu4EkARnbiJ2FKosajpP8eceaL1u4JOelNG+RN7cldvmWEtefZCPNOHAHddQLfEnRZ3xyzdRdV0A3vXykyY6UMWgRlPnHOslAm8OUpOWubDzQTmfr88R38EUrHG4HYvRVmQb/s/LQjsuS863vSbwIDAQAB"
HmPubKeyJBLPubFp = "./config/hm_pay/jbl_pub_private_key.pem"
TestHmPubKeyJBLPubFp = "/Users/max/Documents/code/deovo/mh_goadmin_server/config/hm_pay/jbl_pub_private_key.pem"
)
const (
@ -698,10 +720,9 @@ type HmPayUnifiedOrderRsp struct {
Sign string `json:"sign"`
}
func ParsePrivateKeyDeovo() (*rsa.PrivateKey, error) {
//fp := "/Users/max/Documents/code/deovo/mh_goadmin_server/config/hm_pay/deovo_private_key.pem"
fp := "./config/hm_pay/deovo_private_key.pem"
privateKey, err := os.ReadFile(fp)
func ParsePrivateKeyDeovo(storeId uint32) (*rsa.PrivateKey, error) {
storeKey := getStoreKeyConfig(storeId)
privateKey, err := os.ReadFile(storeKey.FP)
if err != nil {
logger.Errorf("read file err:", err)
return nil, err
@ -722,12 +743,12 @@ func ParsePrivateKeyDeovo() (*rsa.PrivateKey, error) {
return priKey.(*rsa.PrivateKey), nil
}
func Sha1withRsaDeovo(signContent string) (string, error) {
func Sha1withRsaDeovo(storeId uint32, signContent string) (string, error) {
hash := crypto.SHA1
shaNew := hash.New()
shaNew.Write([]byte(signContent))
hashed := shaNew.Sum(nil)
priKey, err := ParsePrivateKeyDeovo()
priKey, err := ParsePrivateKeyDeovo(storeId)
if err != nil {
logger.Errorf("parse err:", err)
return "", err
@ -741,7 +762,7 @@ func Sha1withRsaDeovo(signContent string) (string, error) {
return b64.StdEncoding.EncodeToString(signature), nil
}
func GenHmPaySignDeovo(m map[string]string) (string, error) {
func GenHmPaySignDeovo(storeId uint32, m map[string]string) (string, error) {
delete(m, "sign")
var signData []string
for k, v := range m {
@ -765,7 +786,7 @@ func GenHmPaySignDeovo(m map[string]string) (string, error) {
//logger.Info("签字符串1:", logger.Field("signStr", signStr))
fmt.Println("签字符串1:", signStr)
signature, err := Sha1withRsaDeovo(signStr)
signature, err := Sha1withRsaDeovo(storeId, signStr)
if err != nil {
logger.Errorf("signature err:", err)
return "", err
@ -905,7 +926,7 @@ func HmPayUnifiedOrder(r HmJsPayUnifiedOrderReq) (HmPayUnifiedOrderRsp, error) {
return hmPayUnifiedOrderRsp, nil
}
func HmVerifySha1RsaDeovo(signContent, signBase string) error {
func HmVerifySha1RsaDeovo(storeId uint32, signContent, signBase string) error {
//fp := "/Users/li/mh/mh_server/pack/configs/hm_pay/public_key.pme"
//publicKeyString, err := ioutil.ReadFile(fp)
//if err != nil {
@ -913,7 +934,8 @@ func HmVerifySha1RsaDeovo(signContent, signBase string) error {
// return err
//}
block, _ := pem.Decode([]byte(FormatPrivateKey(HmPubKeyDeovo)))
storeKey := getStoreKeyConfig(storeId)
block, _ := pem.Decode([]byte(FormatPrivateKey(storeKey.PubKey)))
if block == nil {
fmt.Println("decode block is nil")
return errors.New("decode block is nil")
@ -1021,6 +1043,50 @@ func ToSignContent(s interface{}) (string, error) {
return signStr, nil
}
type StoreKeyConfig struct {
AppID string
FP string
PubKey string
}
func getStoreKeyConfig(storeId uint32) StoreKeyConfig {
var config StoreKeyConfig
switch storeId {
case 19, 23, 27, 28: // 汕头万象城, 海雅缤纷城, 布吉万象汇, 大运天地
config = StoreKeyConfig{
AppID: HmPayMerchantIdSwitchPub,
FP: HmPubKeySwitchPubFp,
PubKey: HmPubKeySwitchPub,
}
case 13: // 万象天地
config = StoreKeyConfig{
AppID: HmPayMerchantIdSwitch,
FP: HmPubKeySwitchFp,
PubKey: HmPubKeySwitch,
}
case 29: // JBL哈曼店
now := time.Now()
start := time.Date(now.Year(), now.Month(), now.Day(), 16, 30, 0, 0, now.Location())
end := time.Date(now.Year(), now.Month(), now.Day(), 23, 59, 59, 0, now.Location())
if now.After(start) && now.Before(end) {
config = StoreKeyConfig{
AppID: HmPayMerchantIdJBLPub,
FP: HmPubKeyJBLPubFp,
PubKey: HmPubKeyJBLPub,
}
} else {
config = StoreKeyConfig{
AppID: HmPayMerchantIdJBL,
FP: HmPubKeyJBLFp,
PubKey: HmPubKeyJBL,
}
}
}
return config
}
// HmJsPayBToCOrder 河马刷卡支付B扫C
func HmJsPayBToCOrder(storeId uint32, orderId string, totalFee float64, authCode, notifyUrl string) (*HmPayBToCOrderDetail, error) {
now := time.Now().Local()
@ -1033,9 +1099,11 @@ func HmJsPayBToCOrder(storeId uint32, orderId string, totalFee float64, authCode
// return nil, errors.New("NotifyUrl is null")
//}
storeKey := getStoreKeyConfig(storeId)
unifiedOrderReq := HmJsPayUnifiedOrderReq{}
publicPara := HmPayPublicPara{
AppId: HmPayMerchantIdDeovo,
AppId: storeKey.AppID,
//SubAppId: HmWxSubMerchantId,
Method: "trade.pay",
//Charset: "UTF-8",
@ -1080,7 +1148,7 @@ func HmJsPayBToCOrder(storeId uint32, orderId string, totalFee float64, authCode
return nil, err
}
sign, err := GenHmPaySignDeovo(m)
sign, err := GenHmPaySignDeovo(storeId, m)
if err != nil {
logger.Error("HmJsPayUnifiedOrder GenHmPaySign err:", logger.Field("err", err))
return nil, err
@ -1099,7 +1167,7 @@ func HmJsPayBToCOrder(storeId uint32, orderId string, totalFee float64, authCode
return nil, err
}
err = HmVerifySha1RsaDeovo(signContent, unifiedOrderResp.Sign)
err = HmVerifySha1RsaDeovo(storeId, signContent, unifiedOrderResp.Sign)
if err != nil {
logger.Errorf("HmVerifySha1Rsa err:", err)
return nil, err
@ -1118,13 +1186,14 @@ func HmJsPayBToCOrder(storeId uint32, orderId string, totalFee float64, authCode
}
// HmQueryOrder 订单查询
func HmQueryOrder(orderId string) (*HmPayTradeQueryResp, error) {
func HmQueryOrder(orderId string, storeId uint32) (*HmPayTradeQueryResp, error) {
now := time.Now().Local()
nonce := GenRandStr(NonceStringLength)
storeKey := getStoreKeyConfig(storeId)
unifiedOrderReq := HmJsPayUnifiedOrderReq{}
publicPara := HmPayPublicPara{
AppId: HmPayMerchantIdDeovo,
AppId: storeKey.AppID,
Method: "trade.query",
SignType: "RSA",
Sign: "",
@ -1149,7 +1218,7 @@ func HmQueryOrder(orderId string) (*HmPayTradeQueryResp, error) {
return nil, err
}
sign, err := GenHmPaySignDeovo(m)
sign, err := GenHmPaySignDeovo(storeId, m)
if err != nil {
logger.Error("HmJsPayUnifiedOrder GenHmPaySign err:", logger.Field("err", err))
return nil, err
@ -1167,7 +1236,7 @@ func HmQueryOrder(orderId string) (*HmPayTradeQueryResp, error) {
logger.Errorf("ToSignContent err:", err)
return nil, err
}
err = HmVerifySha1RsaDeovo(signContent, unifiedOrderResp.Sign)
err = HmVerifySha1RsaDeovo(storeId, signContent, unifiedOrderResp.Sign)
if err != nil {
logger.Errorf("HmVerifySha1Rsa err:", err)
return nil, err
@ -1187,13 +1256,13 @@ func HmQueryOrder(orderId string) (*HmPayTradeQueryResp, error) {
}
// HmCancelOrder 订单撤销
func HmCancelOrder(orderId string) (*HmPayTradeCancelResp, error) {
func HmCancelOrder(orderId string, storeId uint32) (*HmPayTradeCancelResp, error) {
now := time.Now().Local()
nonce := GenRandStr(NonceStringLength)
unifiedOrderReq := HmJsPayUnifiedOrderReq{}
publicPara := HmPayPublicPara{
AppId: HmPayMerchantIdDeovo,
AppId: HmPayMerchantIdSwitch,
Method: "trade.cancel",
SignType: "RSA",
Sign: "",
@ -1218,7 +1287,7 @@ func HmCancelOrder(orderId string) (*HmPayTradeCancelResp, error) {
return nil, err
}
sign, err := GenHmPaySignDeovo(m)
sign, err := GenHmPaySignDeovo(storeId, m)
if err != nil {
logger.Error("HmJsPayUnifiedOrder GenHmPaySign err:", logger.Field("err", err))
return nil, err
@ -1236,7 +1305,7 @@ func HmCancelOrder(orderId string) (*HmPayTradeCancelResp, error) {
logger.Errorf("ToSignContent err:", err)
return nil, err
}
err = HmVerifySha1RsaDeovo(signContent, unifiedOrderResp.Sign)
err = HmVerifySha1RsaDeovo(storeId, signContent, unifiedOrderResp.Sign)
if err != nil {
logger.Errorf("HmVerifySha1Rsa err:", err)
return nil, err

View File

@ -43,7 +43,7 @@ func TestHmJsPayBToCOrder(t *testing.T) {
func TestHmQueryOrder(t *testing.T) {
orderId := "sale2024070569804727"
order, err := HmQueryOrder(orderId)
order, err := HmQueryOrder(orderId, 13)
if err != nil {
fmt.Println("err:", err)
}
@ -55,7 +55,7 @@ func TestHmQueryOrder(t *testing.T) {
func TestHmCancelOrder(t *testing.T) {
orderId := "sale2023122225067733"
order, err := HmCancelOrder(orderId)
order, err := HmCancelOrder(orderId, 13)
if err != nil {
fmt.Println("err:", err)
}

View File

@ -814,7 +814,7 @@ func ErpPurchaseReportByCommodity(c *gin.Context) {
app.Error(c, http.StatusInternalServerError, err, "查询失败:"+err.Error())
return
}
fmt.Println(resp)
//fmt.Println(resp)
app.OK(c, resp, "查询成功")
return

View File

@ -2,6 +2,7 @@ package system
import (
"encoding/json"
"fmt"
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin/binding"
"github.com/google/uuid"
@ -25,6 +26,8 @@ import (
// @Param roleId query string false "角色id"
// @Param nickName query string false "昵称"
// @Param storeId query string false "门店id"
// @Param shopper_code query string false "店员兑换码"
// @Param is_export query string false "是否导出1-导出"
// @Success 200 {object} models.SysUserListResp
// @Router /api/v1/sysUserList [get]
// @Security Bearer
@ -43,17 +46,20 @@ func GetSysUserList(c *gin.Context) {
if index != "" {
pageIndex, err = tools.StringToInt(index)
}
data.Username = c.Request.FormValue("username") // 用户名称
data.Status = c.Request.FormValue("status") // 状态
data.Phone = c.Request.FormValue("phone") // 手机号
strRoleId := c.Request.FormValue("roleId") // 用户角色
data.RoleId, _ = tools.StringToInt(strRoleId)
data.NickName = c.Request.FormValue("nickName") // 用户昵称
strStoreId := c.Request.FormValue("storeId") // 门店id
data.ShopperCode = c.Request.FormValue("shopper_code") // 店员兑换码
exportFlag := c.Request.FormValue("is_export") // 是否导出excel
export := 0
if exportFlag != "" {
export, _ = tools.StringToInt(exportFlag)
}
data.RoleId, _ = tools.StringToInt(strRoleId)
nStoreId, _ := tools.StringToInt(strStoreId)
data.StoreId = uint32(nStoreId)
@ -64,10 +70,17 @@ func GetSysUserList(c *gin.Context) {
data.DeptId, _ = tools.StringToInt(deptId)
data.DataScope = tools.GetUserIdStr(c)
result, count, err := data.GetPage(pageSize, pageIndex)
result, count, exportUrl, err := data.GetPage(pageSize, pageIndex, export)
tools.HasError(err, "", -1)
var resp models.SysUserListResp
resp.List = result
resp.ExportUrl = exportUrl
resp.Total = count
resp.PageSize = pageSize
resp.PageIndex = pageIndex
app.PageOK(c, result, count, pageIndex, pageSize, "")
app.OK(c, resp, "查询成功")
return
}
// GetSysUser
@ -182,6 +195,27 @@ func InsertSysUser(c *gin.Context) {
tools.HasError(err, "数据解析失败", 500)
}
if req.ShopperCode != "" {
if len(req.ShopperCode) != 6 {
logger.Error("兑换码不是6位")
app.Error(c, http.StatusInternalServerError, err, "兑换码长度不符合要求[6位]")
return
}
if req.Uid == 0 {
logger.Error("uid为0")
app.Error(c, http.StatusInternalServerError, err, "配置店员兑换码需填写小程序账号ID")
return
}
// 判断店员兑换码是否重复
if models.IsShopperCodeExists(req.ShopperCode) {
logger.Error("兑换码重复")
app.Error(c, http.StatusInternalServerError, err, fmt.Sprintf("兑换码[%s]重复,请更换", req.ShopperCode))
return
}
}
// 判断小程序账号ID是否正常
if req.Uid != 0 {
userInfo, err := models.GetUserInfoByUid(req.Uid)
@ -259,6 +293,16 @@ func InsertSysUser(c *gin.Context) {
}
}
if req.ShopperCode != "" {
err = models.AddShopperCode(req, begin)
if err != nil {
begin.Rollback()
logger.Error("AddShopperCode err:", logger.Field("err", err))
app.Error(c, http.StatusInternalServerError, err, err.Error())
return
}
}
err = begin.Commit().Error
if err != nil {
begin.Rollback()
@ -286,13 +330,37 @@ func UpdateSysUser(c *gin.Context) {
err := c.BindWith(&req, binding.JSON)
tools.HasError(err, "非法数据格式", 500)
if req.ShopperCode != "" {
if len(req.ShopperCode) != 6 {
logger.Error("兑换码不是6位")
app.Error(c, http.StatusInternalServerError, err, "店员识别码长度不符合要求[6位]")
return
}
if req.Uid == 0 {
logger.Error("uid为0")
app.Error(c, http.StatusInternalServerError, err, "配置店员识别码需填写小程序账号ID")
return
}
}
SalesCommRateFloat, err := models.StringToFloat(req.SalesCommRate)
if err != nil {
//logger.Error("brokerage1 err:", err)
tools.HasError(err, "数据解析失败", 500)
}
sysInfo := models.GetUserById(uint32(req.UserId))
sysInfo := models.GetSysUserById(uint32(req.UserId))
if sysInfo.Uid != 0 {
// 添加店员兑换码
var shopperCode models.ShopperPromotionCode
err = orm.Eloquent.Table("shopper_promotion_code").Where("uid = ?", sysInfo.Uid).Find(&shopperCode).Error
if err != nil {
logger.Error("query shopper_promotion_code err:", logger.Field("err", err))
}
sysInfo.ShopperCode = shopperCode.Code
}
// 判断小程序账号ID是否正常
if req.Uid != 0 && sysInfo.Uid != req.Uid {
userInfo, err := models.GetUserInfoByUid(req.Uid)
@ -336,6 +404,11 @@ func UpdateSysUser(c *gin.Context) {
},
}
// 重置密码时uid赋值为原有的uid
if req.Phone == "" && req.LoginM.PassWord.Password != "" && req.Uid == 0 {
data.Uid = sysInfo.Uid
}
if len(req.StoreList) != 0 {
// 将 StoreData 转换为 JSON 字符串
storeDataJSON, err := json.Marshal(req.StoreList)
@ -350,26 +423,25 @@ func UpdateSysUser(c *gin.Context) {
begin := orm.Eloquent.Begin()
data.UpdateBy = tools.GetUserIdStr(c)
result, err := data.Update(begin, data.UserId)
if err != nil {
begin.Rollback()
}
tools.HasError(err, "修改失败", 500)
// 判断是否修改了uid
if req.Phone != "" { // 手机号目前是必填项,不能为空,否则可能是重置密码
if sysInfo.Uid == 0 && req.Uid != 0 { // 新增uid直接更新为2即可
err = models.UpdateUserType(begin, req.Uid, models.UserTypeShopAssistant, uint32(req.RoleId))
} else if sysInfo.Uid != 0 {
if sysInfo.Uid != req.Uid {
// 原uid的状态更新为1
err = models.UpdateUserType(begin, sysInfo.Uid, models.UserTypeConsumer, 0)
if err != nil {
begin.Rollback()
logger.Error("UpdateUserType err:", logger.Field("err", err))
app.Error(c, http.StatusInternalServerError, err, "修改失败")
return
}
if err == nil {
if req.Uid != 0 {
// 新uid状态更新为2
err = models.UpdateUserType(begin, req.Uid, models.UserTypeShopAssistant, uint32(req.RoleId))
}
}
} else if sysInfo.Uid == req.Uid && sysInfo.RoleId != req.RoleId { // 更改了用户角色
err = models.UpdateUserType(begin, sysInfo.Uid, models.UserTypeShopAssistant, uint32(req.RoleId))
}
@ -380,6 +452,17 @@ func UpdateSysUser(c *gin.Context) {
app.Error(c, http.StatusInternalServerError, err, "修改失败")
return
}
}
if req.ShopperCode != "" { // 添加店员兑换码:删除原兑换码,添加新兑换码
err = models.UpdateShopperCode(req, begin, sysInfo)
if err != nil {
begin.Rollback()
logger.Error("UpdateShopperCode err:", logger.Field("err", err))
app.Error(c, http.StatusInternalServerError, err, err.Error())
return
}
}
err = begin.Commit().Error
if err != nil {

View File

@ -11,6 +11,7 @@ import (
"go-admin/tools/config"
"golang.org/x/sync/errgroup"
"gorm.io/gorm"
"math"
"math/rand"
"sort"
"strconv"
@ -35,9 +36,6 @@ const (
SystemOut = 5 // 系统出库
CheckOut = 6 // 盘点出库
OnSale = 7 // 销售锁定中
PurchasePrice = "erp:stock:stockDetails:list:purchasePrice" // 入库采购价
EmployeeCostPrice = "erp:stock:stockDetails:list:employeeCostPrice" // 入库员工成本价
)
// ErpStock 库存列表
@ -56,7 +54,8 @@ type ErpStock struct {
MinRetailPrice float64 `json:"min_retail_price"` // 最低零售价
Count uint32 `json:"count"` // 数量
DispatchCount uint32 `json:"dispatch_count"` // 调拨中数量(调拨中调入)
Commodities []ErpStockCommodity `json:"commodities" gorm:"-"`
Commodities []ErpStockCommodity `json:"commodities" gorm:"-"` //
DecisionStoreId []uint32 `json:"decision_store_id" gorm:"-"` // 门店编号列表(查询进销存的时候使用)
}
// ErpStockCommodity 库存详情
@ -122,6 +121,7 @@ type ErpCommodity struct {
Origin string `json:"origin"` // 产地
Remark string `json:"remark" gorm:"type:varchar(512)"` // 备注
StockCount uint32 `json:"stock_count" gorm:"-"` // 库存数量
Img string `json:"img"` // 图片
ErpCategory *ErpCategory `json:"erp_category" gorm:"-"`
}
@ -509,6 +509,10 @@ func (m *ErpCommodityListReq) List() (*ErpCommodityListResp, error) {
// 计算分页所需的切片索引
startIndex := page * m.PageSize
if (len(commodities)/m.PageSize + 1) < startIndex {
startIndex = 0
page = 0
}
endIndex := (page + 1) * m.PageSize
if endIndex > len(commodities) {
endIndex = len(commodities)
@ -523,6 +527,44 @@ func (m *ErpCommodityListReq) List() (*ErpCommodityListResp, error) {
return resp, nil
}
// SortByErpSupplierId 对商品数组进行排序先按供应商ID排序如果相同则按商品编号排序升序
func SortByErpSupplierId(commodities []ErpCommodity, supplierIDDesc bool) {
// 定义排序函数
less := func(i, j int) bool {
// 按照供应商ID排序
if commodities[i].ErpSupplierId != commodities[j].ErpSupplierId {
if supplierIDDesc { // 降序 DESC
return commodities[i].ErpSupplierId > commodities[j].ErpSupplierId
}
return commodities[i].ErpSupplierId < commodities[j].ErpSupplierId // 升序 ASC
}
// 解析商品编号,提取分类编号和商品编号的数字部分
catNumI, subCatNumI, threeSubCatNumI, itemNumI := parseSerialNumber(commodities[i].SerialNumber)
catNumJ, subCatNumJ, threeSubCatNumJ, itemNumJ := parseSerialNumber(commodities[j].SerialNumber)
// 按照分类编号从小到大排序
if catNumI != catNumJ {
return catNumI < catNumJ
}
// 如果分类编号相同,按照具体分类下的商品编号递增排序
if subCatNumI != subCatNumJ {
return subCatNumI < subCatNumJ
}
if threeSubCatNumI != threeSubCatNumJ {
return threeSubCatNumI < threeSubCatNumJ
}
// 如果具体分类编号也相同,按照商品编号递增排序
return itemNumI < itemNumJ
}
// 调用排序函数进行排序
sort.SliceStable(commodities, less)
}
// SortStockCommodities 对库存商品数组进行排序
func SortStockCommodities(commodities []ErpStock) {
// 定义排序函数
@ -1191,13 +1233,13 @@ func (m *StockImporter) processErpStocks(erpStocks []ErpStockCommodity) error {
})
}
err := m.ErpStockCountUpdate(begin) //更新or插入库存表
err := errGroup.Wait()
if err != nil {
begin.Rollback()
return err
}
err = errGroup.Wait()
err = m.ErpStockCountUpdate(begin) //更新or插入库存表
if err != nil {
begin.Rollback()
return err
@ -1221,8 +1263,26 @@ func createStockList(begin *gorm.DB, stockList []ErpStockCommodity) error {
return nil
}
// 合并导入数据的辅助函数
func mergeCensusMap(censusMap map[uint32]map[uint32]uint32) map[uint32]map[uint32]uint32 {
mergedMap := make(map[uint32]map[uint32]uint32)
for storeId, commodities := range censusMap {
if mergedMap[storeId] == nil {
mergedMap[storeId] = make(map[uint32]uint32)
}
for commodityId, count := range commodities {
mergedMap[storeId][commodityId] += count
}
}
return mergedMap
}
func (m *StockImporter) ErpStockCountUpdate(gdb *gorm.DB) error {
for k1, v1 := range m.CensusMap {
// 合并导入数据,避免同一商品多次重复处理
mergedCensusMap := mergeCensusMap(m.CensusMap)
//for k1, v1 := range m.CensusMap {
for k1, v1 := range mergedCensusMap {
for k2, v2 := range v1 {
exist, err := QueryRecordExist(fmt.Sprintf("SELECT * FROM erp_stock WHERE store_id=%d AND erp_commodity_id=%d", k1, k2))
if err != nil {
@ -1408,44 +1468,85 @@ func ErpStockCommodityToInventory(inventoryStockIdMap map[string]uint32, list []
// ErpCommodityListExport 导出商品列表
func ErpCommodityListExport(list []ErpCommodity) (string, error) {
file := excelize.NewFile()
streamWriter, err := file.NewStreamWriter("Sheet1")
if err != nil {
fmt.Println(err)
}
fSheet := "Sheet1"
url := ExportUrl
fileName := time.Now().Format(TimeFormat) + "商品" + ".xlsx"
fileName := time.Now().Format(TimeFormat) + "商品资料" + ".xlsx"
//title := []interface{}{"供应商编号", "供应商名称", "联系人", "手机号", "地址", "开户银行", "银行账号", "付款周期/天"}
title := []interface{}{"商品编号", "商品名称", "商品分类", "是否串码", "主供应商", "零售价", "最低零售价", "员工成本价",
"采购价", "提成等级1", "提成等级2", "产地", "备注", "会员折扣(零售价的百分比)"}
cell, _ := excelize.CoordinatesToCellName(1, 1)
if err = streamWriter.SetRow(cell, title); err != nil {
fmt.Println(err)
title := []interface{}{"商品编号", "商品名称", "商品分类", "商品条码", "是否串码", "系统生成串码", "主供应商", "指导零售价",
"最低零售价", "员工成本价加价", "指导采购价", "销售毛利提成", "员工毛利提成", "会员优惠", "产地", "备注"}
for i, _ := range title {
cell, _ := excelize.CoordinatesToCellName(1+i, 1)
err := file.SetCellValue(fSheet, cell, title[i])
if err != nil {
logger.Errorf("file set value err:", err)
}
}
var row []interface{}
nExcelStartRow := 0
for rowId := 0; rowId < len(list); rowId++ {
isIMEI := "否"
if list[rowId].IMEIType == 2 {
systemIMEI := "否"
if list[rowId].IMEIType != 1 { // 非串码
isIMEI = "是"
if list[rowId].IMEIType == 2 { //2-串码(系统生成)
systemIMEI = "是"
}
}
row = []interface{}{list[rowId].SerialNumber, list[rowId].Name, list[rowId].ErpCategoryName,
isIMEI, list[rowId].ErpSupplierName, list[rowId].RetailPrice,
list[rowId].MinRetailPrice, list[rowId].StaffCostPrice, list[rowId].WholesalePrice, list[rowId].Brokerage1,
list[rowId].Brokerage2, list[rowId].Origin, list[rowId].Remark, list[rowId].MemberDiscount}
cell, _ := excelize.CoordinatesToCellName(1, rowId+2)
if err := streamWriter.SetRow(cell, row); err != nil {
fmt.Println(err)
}
}
if err := streamWriter.Flush(); err != nil {
fmt.Println(err)
}
if err := file.SaveAs("/www/server/images/export/" + fileName); err != nil {
//if err := file.SaveAs("./" + fileName); err != nil {
row = []interface{}{
list[rowId].SerialNumber,
list[rowId].Name,
list[rowId].ErpCategoryName,
list[rowId].ErpBarcode,
isIMEI,
systemIMEI,
list[rowId].ErpSupplierName,
list[rowId].RetailPrice,
list[rowId].MinRetailPrice,
list[rowId].StaffCostPrice,
list[rowId].WholesalePrice,
list[rowId].Brokerage1,
list[rowId].Brokerage2,
list[rowId].MemberDiscount,
list[rowId].Origin,
list[rowId].Remark}
for j, _ := range row {
cell, _ := excelize.CoordinatesToCellName(1+j, nExcelStartRow+2)
err := file.SetCellValue(fSheet, cell, row[j])
if err != nil {
logger.Error("file set value err:", logger.Field("err", err))
}
}
nExcelStartRow++
}
// 设置所有单元格的样式: 居中、加边框
style, _ := file.NewStyle(`{"alignment":{"horizontal":"center","vertical":"center"},
"border":[{"type":"left","color":"000000","style":1},
{"type":"top","color":"000000","style":1},
{"type":"right","color":"000000","style":1},
{"type":"bottom","color":"000000","style":1}]}`)
//设置单元格高度
file.SetRowHeight("Sheet1", 1, 20)
// 设置单元格大小
file.SetColWidth("Sheet1", "A", "A", 15)
file.SetColWidth("Sheet1", "B", "B", 30)
file.SetColWidth("Sheet1", "D", "D", 18)
endRow := fmt.Sprintf("P"+"%d", nExcelStartRow+2)
// 应用样式到整个表格
_ = file.SetCellStyle("Sheet1", "A1", endRow, style)
fmt.Println("save fileName:", config.ExportConfig.Path+fileName)
if err := file.SaveAs(config.ExportConfig.Path + fileName); err != nil {
fmt.Println(err)
}
return url + fileName, nil
}
@ -1474,7 +1575,7 @@ func checkRoleMenu(c *gin.Context, menuName string) (bool, error) {
}
// InventoryDetailListExport 导出库存商品列表
func InventoryDetailListExport(list []ErpStockCommodity, exportPurchasePrice bool, exportStaffCostPrice bool) (string, error) {
func InventoryDetailListExport(list []ErpStockCommodity, c *gin.Context) (string, error) {
file := excelize.NewFile()
streamWriter, err := file.NewStreamWriter("Sheet1")
if err != nil {
@ -1483,12 +1584,20 @@ func InventoryDetailListExport(list []ErpStockCommodity, exportPurchasePrice boo
}
url := ExportUrl
fileName := time.Now().Format(TimeFormat) + "商品" + ".xlsx"
fileName := time.Now().Format(TimeFormat) + "库存详情" + ".xlsx"
fmt.Println("url fileName:", url+fileName)
// 判断是否有入库采购价、入库员工成本价的权限
exportPurchasePrice, _ := checkRoleMenu(c, PurchasePrice)
exportStaffCostPrice, _ := checkRoleMenu(c, EmployeeCostPrice)
fmt.Println("exportPurchasePrice is:", exportPurchasePrice)
fmt.Println("exportStaffCostPrice is:", exportStaffCostPrice)
logger.Info("exportPurchasePrice is:", logger.Field("exportPurchasePrice", exportPurchasePrice))
logger.Info("exportStaffCostPrice is:", logger.Field("exportStaffCostPrice", exportStaffCostPrice))
// 设置标题行
title := []interface{}{"商品编号", "商品名称", "商品分类", "是否串码", "商品串码", "所属门店", "供应商", "首次入库时间", "首次入库方式",
"首次入库订单编号", "最近入库时间"}
title := []interface{}{"商品编号", "商品名称", "商品分类", "是否串码", "商品串码", "所属门店", "供应商", "库存数量",
"首次入库时间", "首次入库方式", "首次入库订单编号", "最近入库时间"}
if exportPurchasePrice {
title = append(title, "入库采购价")
@ -1540,6 +1649,7 @@ func InventoryDetailListExport(list []ErpStockCommodity, exportPurchasePrice boo
list[rowId].IMEI,
list[rowId].StoreName,
list[rowId].ErpSupplierName,
1,
list[rowId].FirstStockTime,
storageType,
list[rowId].OriginalSn,
@ -1559,19 +1669,19 @@ func InventoryDetailListExport(list []ErpStockCommodity, exportPurchasePrice boo
row = append(row, state)
row = append(row, list[rowId].Remark)
cell, _ := excelize.CoordinatesToCellName(1, rowId+2)
if err := streamWriter.SetRow(cell, row); err != nil {
cell, _ = excelize.CoordinatesToCellName(1, rowId+2)
if err = streamWriter.SetRow(cell, row); err != nil {
fmt.Println(err)
return "", err
}
}
if err := streamWriter.Flush(); err != nil {
if err = streamWriter.Flush(); err != nil {
fmt.Println(err)
return "", err
}
fmt.Println("save fileName:", config.ExportConfig.Path+fileName)
if err := file.SaveAs(config.ExportConfig.Path + fileName); err != nil {
if err = file.SaveAs(config.ExportConfig.Path + fileName); err != nil {
fmt.Println(err)
return "", err
}
@ -2349,8 +2459,8 @@ type ErpStockCommodityListResp struct {
Total int `json:"total"` // 数据总条数
PageIndex int `json:"pageIndex"` // 页码
PageSize int `json:"pageSize"` // 每页展示条数
TotalWholesalePrice int `json:"total_wholesale_price"` // 入库采购价之和
TotalStaffPrice int `json:"total_staff_price"` // 入库员工成本价之和
TotalWholesalePrice float64 `json:"total_wholesale_price"` // 入库采购价之和
TotalStaffPrice float64 `json:"total_staff_price"` // 入库员工成本价之和
ExportUrl string `json:"export_url"`
}
@ -2431,14 +2541,8 @@ func (m *ErpStockCommodityListReq) GetDetailList(c *gin.Context, nType uint32) (
return resp, err
}
ErpStockCommodityListSetAge(commodities)
// 判断是否有入库采购价、入库员工成本价的权限
purchasePriceFlag, _ := checkRoleMenu(c, PurchasePrice)
employeeCostPriceFlag, _ := checkRoleMenu(c, EmployeeCostPrice)
fmt.Println("purchasePriceFlag is:", purchasePriceFlag)
fmt.Println("employeeCostPriceFlag is:", employeeCostPriceFlag)
logger.Info("purchasePriceFlag is:", logger.Field("purchasePriceFlag", purchasePriceFlag))
logger.Info("employeeCostPriceFlag is:", logger.Field("employeeCostPriceFlag", purchasePriceFlag))
listExport, err := InventoryDetailListExport(commodities, purchasePriceFlag, employeeCostPriceFlag)
listExport, err := InventoryDetailListExport(commodities, c)
if err != nil {
//logger.Error("list export err:", err)
}
@ -2465,8 +2569,8 @@ func (m *ErpStockCommodityListReq) GetDetailList(c *gin.Context, nType uint32) (
resp.Total = int(count)
resp.PageIndex = page + 1
resp.PageSize = m.PageSize
resp.TotalWholesalePrice = int(nTotalCount.TotalWholesalePrice)
resp.TotalStaffPrice = int(nTotalCount.TotalStaffCostPrice + nTotalCount.TotalWholesalePrice)
resp.TotalWholesalePrice = math.Round(nTotalCount.TotalWholesalePrice*100) / 100
resp.TotalStaffPrice = math.Round((nTotalCount.TotalStaffCostPrice+nTotalCount.TotalWholesalePrice)*100) / 100
return resp, nil
}
@ -2714,7 +2818,9 @@ func SetStockCommodityState(c *gin.Context, id uint32) error { //更新库存状
// 更新商品库存详情表状态为:系统出库
if err := begin.Model(&ErpStockCommodity{}).Where("id=?", id).Updates(map[string]interface{}{
"state": SystemOut}).Error; err != nil {
"state": SystemOut,
"updated_at": time.Now(),
}).Error; err != nil {
return fmt.Errorf("[update err]%v", err)
}
@ -3066,7 +3172,8 @@ type CommodityCreateRequest struct {
Brokerage2 float64 `json:"brokerage_2"` // 员工毛利提成
MemberDiscount float64 `json:"member_discount"` // 会员优惠
Origin string `json:"origin"` // 产地
Remark string `json:"remark" gorm:"type:varchar(512)"` // 备注
Remark string `json:"remark"` // 备注
Img string `json:"img"` // 图片
}
type CommodityEditRequest struct {
@ -3085,7 +3192,8 @@ type CommodityEditRequest struct {
Brokerage2 float64 `json:"brokerage_2"` // 员工毛利提成
MemberDiscount float64 `json:"member_discount"` // 会员优惠
Origin string `json:"origin"` // 产地
Remark string `json:"remark" gorm:"type:varchar(512)"` // 备注
Remark string `json:"remark"` // 备注
Img string `json:"img"` // 图片
}
type CommodityDetailRequest struct {

View File

@ -12,18 +12,19 @@ const (
type Coupon struct {
Model
Name string `json:"name"`
Describe string `json:"describe" gorm:"type:text;"` // 描述
CouponType string `json:"coupon_type"`
Name string `json:"name"` // 优惠券名称
Describe string `json:"describe" gorm:"type:text"` // 优惠券简介
Rule string `json:"rule" gorm:"type:text"` // 优惠券使用规则
CouponType string `json:"coupon_type"` //
ActivityType uint32 `json:"activity_type"` // 活动类型 1-会员续费
ActivityId uint32 `json:"activity_id" gorm:"index"`
Value uint32 `json:"value"`
ActivityId uint32 `json:"activity_id" gorm:"index"` //
Value uint32 `json:"value"` //
OutCount uint32 `json:"out_count"` // 用户已领取数量
UsedCount uint32 `json:"used_count"` // 用户已使用数量
ActiveStart time.Time `json:"active_start"` // 有效期开始
ActiveEnd time.Time `json:"active_end"` // 有效期结束 零值永不结束
MemberLevel uint32 `json:"member_level"` // 会员等级 1-用户 2-会员
IsDraw bool `json:"is_draw" gorm:"-"`
IsDraw bool `json:"is_draw" gorm:"-"` //
}
// gen:qs

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1557,7 +1557,7 @@ func ExpireMemberSMSSendDay(day uint32, nowTime time.Time) {
//err := orm.Eloquent.Table("user").Where("member_expire > ?", start).Where("member_expire < ?", end).
// Where("member_level in (?)", []uint32{2, 3, 4, 5}).Find(&users).Error
err := orm.Eloquent.Table("user").Where("member_expire > ?", start).Where("member_expire < ?", end).
Where("member_level = ", MemberLevelUser).Find(&users).Error
Where("member_level = ?", MemberLevelUser).Find(&users).Error
if err != nil {
logger.Error(err.Error())
return

View File

@ -142,12 +142,12 @@ func checkAllotInventoryParam(req *InventoryAllotAddReq, editFlag bool) error {
}
}
// 校验编辑订单时是否有传商品ID
if editFlag {
if item.ID == 0 {
return fmt.Errorf("商品[%s]ID为空", item.CommodityName)
}
}
//// 校验编辑订单时是否有传商品ID
//if editFlag {
// if item.ID == 0 {
// return fmt.Errorf("商品[%s]ID为空", item.CommodityName)
// }
//}
// 校验串码类型
switch item.IMEIType {
@ -351,7 +351,7 @@ func EditAllotInventory(req *InventoryAllotEditReq) (*ErpInventoryAllotOrder, er
inventoryAllotOrder.TotalCount = nTotalCount
err = begin.Model(&ErpInventoryAllotOrder{}).Where("id = ?", inventoryAllotOrder.ID).
Updates(inventoryAllotOrder).Error
Omit("created_at").Save(inventoryAllotOrder).Error
if err != nil {
begin.Rollback()
logger.Error("update allot order err:", logger.Field("err", err))
@ -786,6 +786,33 @@ func MergeCommodities(commodities []ErpInventoryAllotCommodity) []ErpInventoryAl
return mergedCommodities
}
// MergeAllCommodities 遍历库存调拨商品信息将商品id相同的所有商品进行合并数量累加即可
func MergeAllCommodities(commodities []ErpInventoryAllotCommodity) []ErpInventoryAllotCommodity {
// 用于存储合并后的商品信息
mergedCommodities := make([]ErpInventoryAllotCommodity, 0)
// 用于记录无串码商品的合并信息
commodityMap := make(map[uint32]*ErpInventoryAllotCommodity)
for _, commodity := range commodities {
if existing, found := commodityMap[commodity.CommodityId]; found {
// 如果相同商品 ID 的无串码商品已存在,则数量累加
existing.Count += commodity.Count
commodityMap[commodity.CommodityId] = existing
} else {
// 否则,加入到 commodityMap 中
newCommodity := commodity
commodityMap[commodity.CommodityId] = &newCommodity
}
}
// 将合并后的无串码商品加入到合并后的列表中
for _, commodity := range commodityMap {
mergedCommodities = append(mergedCommodities, *commodity)
}
return mergedCommodities
}
// MergeChangeCommodities 遍历库存变动商品信息将商品id相同的非串码商品进行合并数量累加即可
func MergeChangeCommodities(commodities []ErpInventoryChangeCommodity) []ErpInventoryChangeCommodity {
// 用于存储合并后的商品信息
@ -843,7 +870,7 @@ func cancelAllotAuditAndUpdateStock(gdb *gorm.DB, allotOrder ErpInventoryAllotOr
for _, v := range trimCommodities {
var stockCommodity []ErpStockCommodity
err := orm.Eloquent.Table("erp_stock_commodity").Where("erp_commodity_id = ? AND store_id = ? "+
"AND state = ? AND imei = ?", v.CommodityId, allotOrder.ReceiveStoreId, InAllot, v.IMEI).
"AND state = ? AND imei = ?", v.CommodityId, allotOrder.DeliverStoreId, InAllot, v.IMEI).
Find(&stockCommodity).Error
if err != nil {
return fmt.Errorf("查询商品库存失败:[%s]", err.Error())
@ -1043,13 +1070,15 @@ func ReceiveAllotInventory(req *InventoryAllotReceiveReq, c *gin.Context) error
// 遍历库存调拨商品信息
for _, v := range trimCommodities {
var stockCommodity []ErpStockCommodity
err := orm.Eloquent.Table("erp_stock_commodity").Where("erp_commodity_id = ? AND store_id = ? "+
err = orm.Eloquent.Table("erp_stock_commodity").Where("erp_commodity_id = ? AND store_id = ? "+
"AND state = ? AND imei = ?", v.CommodityId, inventoryAllotOrder.DeliverStoreId, InAllot, v.IMEI).
Find(&stockCommodity).Error
if err != nil {
begin.Rollback()
return fmt.Errorf("查询商品库存失败:[%s]", err.Error())
}
if len(stockCommodity) == 0 {
begin.Rollback()
return fmt.Errorf("未找到商品库存信息")
}
@ -1059,15 +1088,42 @@ func ReceiveAllotInventory(req *InventoryAllotReceiveReq, c *gin.Context) error
stockCommodity[i].StoreName = inventoryAllotOrder.ReceiveStoreName
stockCommodity[i].State = InStock
stockCommodity[i].StockTime = time.Now()
err = begin.Model(&ErpStockCommodity{}).Where("id = ?", stockCommodity[i].ID).
Updates(stockCommodity[i]).Error
err = begin.Where("id", stockCommodity[i].ID).Omit("created_at").Save(&stockCommodity[i]).Error
//err = begin.Model(&ErpStockCommodity{}).Where("id = ?", stockCommodity[i].ID).
// Updates(stockCommodity[i]).Error
if err != nil {
begin.Rollback()
return fmt.Errorf("更新商品库存失败:%s", err.Error())
}
}
}
// 更新库存商品数量
// 遍历库存调拨商品信息将商品id相同的非串码商品进行合并数量累加即可
trimAllCommodities := MergeAllCommodities(trimCommodities)
for _, v := range trimAllCommodities {
var stockCommodity []ErpStockCommodity
err = orm.Eloquent.Table("erp_stock_commodity").Where("erp_commodity_id = ? AND store_id = ? "+
"AND state = ? AND imei = ?", v.CommodityId, inventoryAllotOrder.DeliverStoreId, InAllot, v.IMEI).
Find(&stockCommodity).Error
if err != nil {
begin.Rollback()
return fmt.Errorf("查询商品库存失败:[%s]", err.Error())
}
if len(stockCommodity) == 0 {
begin.Rollback()
return fmt.Errorf("未找到商品库存信息")
}
// 更新调入门店的库存数量
exist, err := QueryRecordExist(fmt.Sprintf("SELECT * FROM erp_stock WHERE store_id=%d AND erp_commodity_id=%d",
inventoryAllotOrder.ReceiveStoreId, v.CommodityId))
if err != nil {
begin.Rollback()
logger.Errorf("exist err:", err)
return err
}
if exist {
// 更新调入门店库存商品数量
err = begin.Exec(fmt.Sprintf(
"UPDATE erp_stock SET count=count+%d WHERE store_id=%d AND erp_commodity_id=%d",
v.Count, inventoryAllotOrder.ReceiveStoreId, v.CommodityId)).Error
@ -1076,12 +1132,45 @@ func ReceiveAllotInventory(req *InventoryAllotReceiveReq, c *gin.Context) error
logger.Errorf("update stock err:", err)
return err
}
} else {
stock := &ErpStock{
StoreId: inventoryAllotOrder.ReceiveStoreId,
StoreName: inventoryAllotOrder.ReceiveStoreName,
ErpCommodityId: v.CommodityId,
ErpCommodityName: v.CommodityName,
ErpCategoryId: stockCommodity[0].ErpCategoryId,
ErpCategoryName: stockCommodity[0].ErpCategoryName,
CommoditySerialNumber: stockCommodity[0].CommoditySerialNumber,
IMEIType: v.IMEIType,
RetailPrice: stockCommodity[0].RetailPrice,
MinRetailPrice: stockCommodity[0].MinRetailPrice,
Count: v.Count,
DispatchCount: 0,
}
err = begin.Create(stock).Error
if err != nil {
begin.Rollback()
logger.Errorf("create stock err:", err)
return err
}
}
// 更新库存商品调拨数量
//// 更新库存商品数量
//err = begin.Exec(fmt.Sprintf(
// "UPDATE erp_stock SET count=count+%d WHERE store_id=%d AND erp_commodity_id=%d",
// v.Count, inventoryAllotOrder.ReceiveStoreId, v.CommodityId)).Error
//if err != nil {
// begin.Rollback()
// logger.Errorf("update stock err:", err)
// return err
//}
// 更新调出门店库存商品调拨数量
err = begin.Exec(fmt.Sprintf(
"UPDATE erp_stock SET dispatch_count = dispatch_count-%d WHERE store_id=%d AND erp_commodity_id=%d",
v.Count, inventoryAllotOrder.DeliverStoreId, v.CommodityId)).Error
if err != nil {
begin.Rollback()
logger.Errorf("update stock err:", err)
return err
}

View File

@ -215,6 +215,17 @@ func checkChangeInventoryParam(req *InventoryChangeAddReq, editFlag bool) error
if stockCount < int64(item.Count) {
return fmt.Errorf("商品[%s]库存数量[%d]少于库存减少数量[%d]", item.CommodityName, stockCount, item.Count)
}
} else { // 库存增加
// 如果该商品是串码商品,判断其串码是否会重复
if item.IMEI != "" {
exist, err := QueryRecordExist(fmt.Sprintf("SELECT * FROM erp_stock_commodity WHERE FIND_IN_SET('%s', imei) > 0", item.IMEI))
if err != nil {
logger.Error("exist sn err")
}
if exist {
return fmt.Errorf("串码有重复项请修改[%s]", item.IMEI)
}
}
}
}
@ -345,7 +356,7 @@ func EditChangeInventory(req *InventoryChangeEditReq) (*ErpInventoryChangeOrder,
inventoryChangeOrder.TotalAmount = nTotalAmount
err = begin.Model(&ErpInventoryChangeOrder{}).Where("id = ?", inventoryChangeOrder.ID).
Updates(inventoryChangeOrder).Error
Omit("created_at").Save(inventoryChangeOrder).Error
if err != nil {
begin.Rollback()
logger.Error("update change order err:", logger.Field("err", err))
@ -749,7 +760,7 @@ func handleInventoryReduce(gdb *gorm.DB, changeOrder ErpInventoryChangeOrder) er
usedStockCommodityIdList := make(map[uint32][]uint32) // 记录非串码商品已使用的商品库存表主键id
// 更新库存数量
for i, _ := range trimCommodities {
if trimCommodities[i].IMEIType == 2 { // 串码商品
if trimCommodities[i].IMEIType == 2 || trimCommodities[i].IMEIType == 3 { // 串码商品
if trimCommodities[i].IMEI == "" {
return errors.New("串码为空")
}
@ -772,7 +783,10 @@ func handleInventoryReduce(gdb *gorm.DB, changeOrder ErpInventoryChangeOrder) er
// 更新库存商品状态为:盘点出库
err = gdb.Table("erp_stock_commodity").Where("imei = ?", trimCommodities[i].IMEI).
Updates(map[string]interface{}{"state": CheckOut}).Error
Updates(map[string]interface{}{
"state": CheckOut,
"updated_at": time.Now(),
}).Error
if err != nil {
logger.Error("handleInventoryReduce update erp_stock_commodity err:",
logger.Field("err", err))
@ -825,13 +839,16 @@ func handleInventoryReduce(gdb *gorm.DB, changeOrder ErpInventoryChangeOrder) er
}
err = gdb.Table("erp_stock_commodity").Where("id = ?", rightId).
Updates(map[string]interface{}{"state": CheckOut}).Error // 状态更新为:盘点出库
Updates(map[string]interface{}{
"state": CheckOut,
"updated_at": time.Now(),
}).Error // 状态更新为:盘点出库
if err != nil {
logger.Error("handleInventoryReduce update erp_stock_commodity err:",
logger.Field("err", err))
return err
}
usedStockCommodityIdList[trimCommodities[i].ID] = append(usedStockCommodityIdList[trimCommodities[i].ID], rightId)
usedStockCommodityIdList[trimCommodities[i].CommodityId] = append(usedStockCommodityIdList[trimCommodities[i].CommodityId], rightId)
}
// 更新库存数量:库存数量-count
@ -868,7 +885,7 @@ func handleCancelInventoryAdd(gdb *gorm.DB, changeOrder ErpInventoryChangeOrder)
// 更新库存数量
for i, _ := range trimCommodities {
if trimCommodities[i].IMEIType == 2 { // 串码商品
if trimCommodities[i].IMEIType == 2 || trimCommodities[i].IMEIType == 3 { // 串码商品
if trimCommodities[i].IMEI == "" {
return errors.New("串码为空")
}
@ -953,7 +970,7 @@ func handleCancelInventoryReduce(gdb *gorm.DB, changeOrder ErpInventoryChangeOrd
usedStockCommodityIdList := make(map[uint32][]uint32) // 记录非串码商品已使用的商品库存表主键id
// 更新库存数量
for i, _ := range trimCommodities {
if trimCommodities[i].IMEIType == 2 { // 串码商品
if trimCommodities[i].IMEIType == 2 || trimCommodities[i].IMEIType == 3 { // 串码商品
if trimCommodities[i].IMEI == "" {
return errors.New("串码为空")
}
@ -1022,7 +1039,7 @@ func handleCancelInventoryReduce(gdb *gorm.DB, changeOrder ErpInventoryChangeOrd
return err
}
usedStockCommodityIdList[trimCommodities[i].ID] = append(usedStockCommodityIdList[trimCommodities[i].ID], rightId)
usedStockCommodityIdList[trimCommodities[i].CommodityId] = append(usedStockCommodityIdList[trimCommodities[i].CommodityId], rightId)
}
// 更新库存数量:库存数量+count

View File

@ -213,6 +213,16 @@ func CheckProductInventoryParam(req *ProductInventoryAddReq, editFlag bool) erro
} else {
_, ok := IMEICommodityMap[item.IMEI]
if !ok {
// 如果该商品是串码商品,判断其串码是否会重复
if item.IMEI != "" {
exist, err := QueryRecordExist(fmt.Sprintf("SELECT * FROM erp_stock_commodity WHERE FIND_IN_SET('%s', imei) > 0", item.IMEI))
if err != nil {
logger.Error("exist sn err")
}
if exist {
return fmt.Errorf("串码有重复项请修改[%s]", item.IMEI)
}
}
IMEICommodityMap[item.IMEI] = true
} else {
return fmt.Errorf("串码[%s]有重复项", item.IMEI)
@ -329,7 +339,7 @@ func EditProductInventory(req *ProductInventoryEditReq) (*ErpInventoryProductOrd
inventoryProductOrder.TotalAmount = nTotalAmount
err = begin.Model(&ErpInventoryProductOrder{}).Where("id = ?", inventoryProductOrder.ID).
Updates(inventoryProductOrder).Error
Omit("created_at").Save(inventoryProductOrder).Error
if err != nil {
begin.Rollback()
logger.Error("update erp_order err:", logger.Field("err", err))
@ -526,7 +536,7 @@ func cancelProductAuditAndUpdateStock(gdb *gorm.DB, productOrder ErpInventoryPro
// 更新库存数量
for i, _ := range commodities {
if commodities[i].IMEIType == 2 { // 串码商品
if commodities[i].IMEIType == 2 || commodities[i].IMEIType == 3 { // 串码商品
if commodities[i].IMEI == "" {
return errors.New("串码为空")
}

View File

@ -388,6 +388,7 @@ func (m *InventoryReportByProductReq) ReportByProductList(c *gin.Context) (*Inve
resp.TotalEffectiveAmount = sumData.TotalEffectiveAmount
resp.TotalTransferAmount = sumData.TotalTransferAmount
resp.TotalAmount = resp.TotalEffectiveAmount + resp.TotalTransferAmount
resp.TotalAmount = math.Round(resp.TotalAmount*100) / 100
resp.Total = uint32(len(reportList))
resp.List = reportList

View File

@ -7,6 +7,36 @@ import (
"go-admin/tools"
)
const (
PurchasePrice = "erp:stock:stockDetails:list:purchasePrice" // 库存详情-入库采购价
EmployeeCostPrice = "erp:stock:stockDetails:list:employeeCostPrice" // 库存详情-入库员工成本价
PriceMenu = "erp:purchase:purchaseDetails:list:price" // 采购/退货价
EmployeePriceMenu = "erp:purchase:purchaseDetails:list:employee_price" // 员工成本价
DifferencePriceMenu = "erp:purchase:purchaseDetails:list:difference_price" // 差额
SalesProfitMenu = "erp:retail:storeMangement:salesProfit" // 门店经营-销售毛利
StaffProfitMenu = "erp:retail:storeMangement:staffProfit" // 门店经营-员工毛利
SalesCostMenu = "erp:retail:retailRemittance:salesCost" // 商品零售毛利汇总-销售成本
EmployeeCostMenu = "erp:retail:retailRemittance:staffCost" // 商品零售毛利汇总-员工成本
SalesMarginMenu = "erp:retail:retailRemittance:salesMargin" // 商品零售毛利汇总-销售毛利
EmployeeMarginMenu = "erp:retail:retailRemittance:employeeMargin" // 商品零售毛利汇总-员工毛利
GrossMarginsMenu = "erp:retail:retailRemittance:grossMargins" // 商品零售毛利汇总-销售毛利率
EmployeeGrossMarginsMenu = "erp:retail:retailRemittance:employeeGrossMargins" // 商品零售毛利汇总-员工毛利率
DetailWholesalePriceMenu = "erp:retail:reportForm:retailDetails:wholesalePrice" // 零售明细-采购单价
DetailEmployeeCostMenu = "erp:retail:reportForm:retailDetails:staffPrice" // 零售明细-员工成本价
DetailSalesProfitMenu = "erp:retail:reportForm:retailDetails:salesProfit" // 零售明细-销售毛利
DetailStaffProfitMenu = "erp:retail:reportForm:retailDetails:staffProfit" // 零售明细-员工毛利
DetailTotalSalesProfitMenu = "erp:retail:reportForm:retailDetails:totalSales" // 零售明细-订单总销售毛利
DetailTotalStaffProfitMenu = "erp:retail:reportForm:retailDetails:totalStaff" // 零售明细-订单总员工毛利
DetailSalesProfitPerMenu = "erp:retail:reportForm:retailDetails:salesProfitPer" // 零售明细-销售毛利提成
DetailStaffProfitPerMenu = "erp:retail:reportForm:retailDetails:staffProfitPer" // 零售明细-员工毛利提成
DetailSalesmanPerMenu = "erp:retail:reportForm:retailDetails:salesmanPer" // 零售明细-销售员提成
DetailStorePerMenu = "erp:retail:reportForm:retailDetails:storePer" // 零售明细-门店提成
)
type Menu struct {
MenuId int `json:"menuId" gorm:"primary_key;AUTO_INCREMENT"`
MenuName string `json:"menuName" gorm:"size:128;"`
@ -262,6 +292,7 @@ func (e *Menu) Get() (Menus []Menu, err error) {
}
if err = table.Order("sort").Find(&Menus).Error; err != nil {
//if err = table.Where("visible = 0").Order("sort").Find(&Menus).Error; err != nil {
return
}
return

View File

@ -18,6 +18,7 @@ import (
"go-admin/tools"
"go-admin/tools/config"
"golang.org/x/sync/errgroup"
"strconv"
"time"
)
@ -1553,9 +1554,10 @@ func (m *ExpressNoInfo) SetStore() {
}
}
// FundRecordListReq 财务统计入参
type FundRecordListReq struct {
Uid uint64 `json:"uid" `
FundType string `json:"fund_type"` // -member_gold -member_platinum -member_black_gold
FundType string `json:"fund_type"`
TransactionId string `json:"transaction_id"` // 支付单号
OutTradeNo string `json:"out_trade_no"`
RefundId string `json:"refund_id"`
@ -1564,9 +1566,18 @@ type FundRecordListReq struct {
EndTime time.Time `json:"end_time"` // 结束时间
Page int `json:"pageIndex"`
PageSize int `json:"pageSize"`
IsExport uint32 `json:"is_export"` // 1-导出
}
func (m *FundRecordListReq) List() ([]FundRecord, int64, error) {
type FundRecordListResp struct {
List []FundRecord `json:"list"`
Total int64 `json:"total"` // 总条数
PageIndex int `json:"pageIndex"` // 页码
PageSize int `json:"pageSize"` // 每页展示条数
ExportUrl string `json:"export_url"`
}
func (m *FundRecordListReq) List() ([]FundRecord, int64, string, error) {
var fundRecords []FundRecord
qs := orm.Eloquent.Table("fund_record")
@ -1602,7 +1613,7 @@ func (m *FundRecordListReq) List() ([]FundRecord, int64, error) {
err := qs.Count(&count).Error
if err != nil {
logger.Errorf("err:", logger.Field("err", err))
return fundRecords, 0, err
return fundRecords, 0, "", err
}
if m.PageSize == 0 {
m.PageSize = 10
@ -1613,13 +1624,146 @@ func (m *FundRecordListReq) List() ([]FundRecord, int64, error) {
if page < 0 {
page = 0
}
if m.IsExport == 1 { // 导出excel
err = qs.Order("created_at DESC").Find(&fundRecords).Error
if err != nil {
logger.Errorf("err:", logger.Field("err", err))
return fundRecords, 0, "", err
}
exportUrl, err := fundRecordListExport(fundRecords)
if err != nil {
logger.Errorf("err:", logger.Field("err", err))
return fundRecords, 0, "", err
}
return nil, 0, exportUrl, nil
} else {
err = qs.Order("created_at DESC").Offset(page * pageSize).Limit(pageSize).Find(&fundRecords).Error
if err != nil {
logger.Errorf("err:", logger.Field("err", err))
return fundRecords, 0, err
return fundRecords, 0, "", err
}
}
return fundRecords, count, nil
return fundRecords, count, "", nil
}
// TranslateFundType 将fund_type转换为对应的字符
func TranslateFundType(fundType string) string {
fundTypeMap := map[string]string{
"member_fee": "会员费",
"buy_goods_refund": "商品退货",
"buy_goods": "商品购买",
"buy_goods_cancel": "商品取消",
"recycle_card": "回收卡带",
"postage_package_fee": "购买运费包",
"member_deposit": "押金",
"upgrade_member": "升级会员",
"member_expire_delay": "滞纳金",
"express_fee": "邮费",
"deposit_refund": "退押金",
"express_fee_refund": "退邮费",
"downgrade_renewal": "降级续费",
}
if val, ok := fundTypeMap[fundType]; ok {
return val
}
return "未知类型"
}
// ConvertAmount 将Amount转换为格式化字符串
func ConvertAmount(amount int64) string {
// 转换为以分为单位的小数,保留两位小数
convertedAmount := float64(amount) / 100.0
sign := "+"
if convertedAmount < 0 {
sign = "-"
convertedAmount = -convertedAmount
}
return sign + strconv.FormatFloat(convertedAmount, 'f', 2, 64)
}
// fundRecordListExport 导出财务统计数据
func fundRecordListExport(list []FundRecord) (string, error) {
file := excelize.NewFile()
fSheet := "Sheet1"
url := ExportUrl
fileName := time.Now().Format(TimeFormat) + "财务统计" + ".xlsx"
fmt.Println("url fileName:", url+fileName)
title := []interface{}{"用户ID", "类型", "金额", "商户单号", "交易单号", "退款单号", "付款单号", "创建时间", "备注"}
for i, _ := range title {
cell, _ := excelize.CoordinatesToCellName(1+i, 1)
err := file.SetCellValue(fSheet, cell, title[i])
if err != nil {
logger.Errorf("file set value err:", err)
}
}
var row []interface{}
nExcelStartRow := 0
for rowId := 0; rowId < len(list); rowId++ {
formattedTime := list[rowId].CreatedAt.Format(QueryTimeFormat)
row = []interface{}{
list[rowId].Uid,
TranslateFundType(list[rowId].FundType),
ConvertAmount(list[rowId].Amount),
list[rowId].OutTradeNo,
list[rowId].TransactionId,
list[rowId].RefundId,
list[rowId].PaymentNo,
formattedTime,
list[rowId].Remark,
}
for j, _ := range row {
cell, _ := excelize.CoordinatesToCellName(1+j, nExcelStartRow+2)
err := file.SetCellValue(fSheet, cell, row[j])
if err != nil {
logger.Error("file set value err:", logger.Field("err", err))
}
}
nExcelStartRow++
}
// 设置所有单元格的样式: 居中、加边框
style, _ := file.NewStyle(`{"alignment":{"horizontal":"center","vertical":"center"},
"border":[{"type":"left","color":"000000","style":1},
{"type":"top","color":"000000","style":1},
{"type":"right","color":"000000","style":1},
{"type":"bottom","color":"000000","style":1}]}`)
//设置单元格高度
file.SetRowHeight("Sheet1", 1, 20)
// 设置单元格大小
file.SetColWidth("Sheet1", "A", "A", 10)
file.SetColWidth("Sheet1", "B", "B", 13)
file.SetColWidth("Sheet1", "C", "C", 10)
file.SetColWidth("Sheet1", "D", "D", 16)
file.SetColWidth("Sheet1", "E", "E", 30)
file.SetColWidth("Sheet1", "F", "F", 30)
file.SetColWidth("Sheet1", "G", "G", 30)
file.SetColWidth("Sheet1", "H", "H", 25)
file.SetColWidth("Sheet1", "I", "I", 13)
var endRow string
endRow = fmt.Sprintf("I"+"%d", nExcelStartRow+1)
// 应用样式到整个表格
_ = file.SetCellStyle("Sheet1", "A1", endRow, style)
fmt.Println("save fileName:", config.ExportConfig.Path+fileName)
if err := file.SaveAs(config.ExportConfig.Path + fileName); err != nil {
fmt.Println(err)
}
return url + fileName, nil
}
type CooperativeOrderReq struct {

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
package models
import (
"database/sql"
"fmt"
orm "go-admin/common/global"
"gorm.io/gorm"
"time"
@ -23,13 +23,16 @@ func GetSmsNumberRemaining() int {
now := time.Now()
year, month, _ := now.Date()
var totalUsed sql.NullInt64
nTotalUsed := struct {
TotalUsed int `json:"total_used"`
}{}
// 查询当前年份和月份的短信发送总数
if err := orm.Eloquent.Debug().Model(&SmsSummary{}).
Where("year = ? AND month = ?", year, int(month)).
Select("SUM(used)").
Scan(&totalUsed).Error; err != nil {
Select("SUM(used) as total_used").
Scan(&nTotalUsed).Error; err != nil {
fmt.Println("SQL Error:", err) // 打印 SQL 错误信息
return 0
}
@ -39,7 +42,7 @@ func GetSmsNumberRemaining() int {
nMonthlyLimit = monthlyLimit
}
remaining := nMonthlyLimit - int(totalUsed.Int64)
remaining := nMonthlyLimit - nTotalUsed.TotalUsed
return remaining
}

View File

@ -4,6 +4,9 @@ import (
"encoding/json"
"errors"
"fmt"
"github.com/xuri/excelize/v2"
"go-admin/logger"
"go-admin/tools/config"
"gorm.io/gorm"
"log"
"sort"
@ -68,6 +71,8 @@ type SysUserB struct {
StoreList []StoreInfo `json:"store_list" gorm:"-" ` // 有效门店列表
SalesCommRate float64 `json:"sales_comm_rate"` // 销售提成比例
Uid uint32 `json:"uid" gorm:"column:uid;unique_index"` // 用户uid todo 待添加
ShopperCode string `json:"shopper_code" gorm:"-"` // 店员兑换码
BaseModel
DataScope string `gorm:"-" json:"dataScope"`
@ -108,6 +113,7 @@ type InsertSysUserReq struct {
SalesCommRate string `json:"sales_comm_rate"` // 销售提成比例
StoreList []StoreInfo `json:"store_list"` // 有效门店
Uid uint32 `json:"uid"` // 用户uid
ShopperCode string `json:"shopper_code"` // 店员兑换码
}
func (SysUser) TableName() string {
@ -260,14 +266,32 @@ type SysUserListResp struct {
Total int `json:"count"` // 总条数
PageIndex int `json:"pageIndex"` // 页码
PageSize int `json:"pageSize"` // 页面条数
ExportUrl string `json:"export_url"` // 导出excel路径
List []SysUserPage `json:"list"` // 采购报表信息
}
func (e *SysUser) GetPage(pageSize int, pageIndex int) ([]SysUserPage, int, error) {
func (e *SysUser) GetPage(pageSize int, pageIndex int, exportFlag int) ([]SysUserPage, int, string, error) {
if e.ShopperCode != "" {
var shopperCode ShopperPromotionCode
err := orm.Eloquent.Table("shopper_promotion_code").Where("code = ?", e.ShopperCode).Find(&shopperCode).Error
if err != nil {
logger.Error("query shopper_promotion_code err:", logger.Field("err", err))
return nil, 0, "", err
}
if shopperCode.ID == 0 {
return nil, 0, "", nil
} else {
e.Uid = shopperCode.Uid
}
}
var doc []SysUserPage
table := orm.Eloquent.Select("sys_user.*,sys_dept.dept_name").Table(e.TableName())
table = table.Joins("left join sys_dept on sys_dept.dept_id = sys_user.dept_id") //es := orm.Eloquent.Select("sys_user.*,sys_dept.dept_name").Table(e.TableName()) //es = table.Joins("left join sys_dept on sys_dept.dept_id = sys_user.dept_id")
if e.Uid != 0 {
table = table.Where("uid = ?", e.Uid)
}
if e.Username != "" {
table = table.Where("username = ?", e.Username)
}
@ -300,7 +324,7 @@ func (e *SysUser) GetPage(pageSize int, pageIndex int) ([]SysUserPage, int, erro
dataPermission.UserId, _ = tools.StringToInt(e.DataScope)
table, err := dataPermission.GetDataScope(e.TableName(), table)
if err != nil {
return nil, 0, err
return nil, 0, "", err
}
es := table
@ -308,18 +332,25 @@ func (e *SysUser) GetPage(pageSize int, pageIndex int) ([]SysUserPage, int, erro
err = es.Count(&count).Error
if err != nil {
//logger.Error("count err:", err)
return nil, 0, err
return nil, 0, "", err
}
//if err := table.Offset((pageIndex - 1) * pageSize).Limit(pageSize).Find(&doc).Order("sys_user.created_at DESC").Offset(-1).Limit(-1).Total(&count).Error; err != nil {
// return nil, 0, err
//}
if exportFlag == 1 { // 导出excel
if err = table.Order("sys_user.user_id DESC").Find(&doc).Error; err != nil {
return nil, 0, "", err
}
} else {
if err = table.Order("sys_user.user_id DESC").Offset((pageIndex - 1) * pageSize).Limit(pageSize).Find(&doc).Error; err != nil {
return nil, 0, err
return nil, 0, "", err
}
}
var resp []SysUserPage
var exportUrl string
// 反序列化 StoreData
for i, v := range doc {
if doc[i].StoreData != "" {
@ -340,10 +371,148 @@ func (e *SysUser) GetPage(pageSize int, pageIndex int) ([]SysUserPage, int, erro
}
}
if doc[i].Uid != 0 {
// 添加店员兑换码
var shopperCode ShopperPromotionCode
err = orm.Eloquent.Table("shopper_promotion_code").Where("uid = ?", doc[i].Uid).Find(&shopperCode).Error
if err != nil {
logger.Error("query shopper_promotion_code err:", logger.Field("err", err))
}
doc[i].ShopperCode = shopperCode.Code
}
resp = append(resp, doc[i])
}
return resp, int(count), nil
if exportFlag == 1 { // 导出excel
exportUrl, err = sysUserExport(resp)
if err != nil {
return nil, 0, "", err
}
resp = nil
}
return resp, int(count), exportUrl, nil
}
func getValidStoreNames(storeList []StoreInfo) (string, error) {
var validStoreNames []string
currentTime := time.Now()
for _, store := range storeList {
expireTime, err := time.Parse(StoreDateTimeFormat, store.ExpireTime)
if err != nil {
return "", fmt.Errorf("invalid expire time format for store ID %d: %v", store.StoreID, err)
}
if expireTime.After(currentTime) {
validStoreNames = append(validStoreNames, store.StoreName)
}
}
return strings.Join(validStoreNames, ","), nil
}
// 导出系统用户列表
func sysUserExport(req []SysUserPage) (string, error) {
file := excelize.NewFile()
fSheet := "Sheet1"
url := ExportUrl
fileName := time.Now().Format(TimeFormat) + "系统用户" + ".xlsx"
fmt.Println("url fileName:", url+fileName)
// 组合标题栏数据
title := []interface{}{"用户名称", "用户昵称", "角色", "合作商", "门店", "手机号", "店员识别码", "状态"}
for i, _ := range title {
cell, _ := excelize.CoordinatesToCellName(1+i, 1)
err := file.SetCellValue(fSheet, cell, title[i])
if err != nil {
logger.Errorf("file set value err:", err)
}
}
// 查询系统角色
var doc []SysRole
err := orm.Eloquent.Table("sys_role").Find(&doc).Error
if err != nil {
logger.Errorf("query sys_role error:", err)
}
roleMap := make(map[int]string)
for _, item := range doc {
roleMap[item.RoleId] = item.RoleName
}
var row []interface{}
nExcelStartRow := 0
for _, userData := range req {
// 门店
storeName, _ := getValidStoreNames(userData.StoreList)
var status string
if userData.Status == "0" {
status = "正常"
} else {
status = "停用"
}
row = []interface{}{
userData.UserName.Username, // 用户名称
userData.NickName, // 用户昵称
roleMap[userData.RoleId], // 角色
userData.CooperativeName, // 合作商
storeName, // 门店
userData.Phone, // 手机号
userData.ShopperCode, // 店员识别码
status, // 状态
}
for j, _ := range row {
cell, _ := excelize.CoordinatesToCellName(1+j, nExcelStartRow+2)
err := file.SetCellValue(fSheet, cell, row[j])
if err != nil {
logger.Error("file set value err:", logger.Field("err", err))
}
}
nExcelStartRow++
}
// 设置所有单元格的样式: 居中、加边框
style, _ := file.NewStyle(`{"alignment":{"horizontal":"center","vertical":"center"},
"border":[{"type":"left","color":"000000","style":1},
{"type":"top","color":"000000","style":1},
{"type":"right","color":"000000","style":1},
{"type":"bottom","color":"000000","style":1}]}`)
// 设置单元格的样式: 居中、加边框、自动换行
style1, _ := file.NewStyle(`{"alignment":{"horizontal":"center","vertical":"center","wrap_text":true},
"border":[{"type":"left","color":"000000","style":1},
{"type":"top","color":"000000","style":1},
{"type":"right","color":"000000","style":1},
{"type":"bottom","color":"000000","style":1}]}`)
//设置单元格高度
file.SetRowHeight("Sheet1", 1, 20)
// 设置单元格大小
file.SetColWidth("Sheet1", "B", "B", 15)
file.SetColWidth("Sheet1", "C", "C", 15)
file.SetColWidth("Sheet1", "D", "D", 15)
file.SetColWidth("Sheet1", "E", "E", 30)
file.SetColWidth("Sheet1", "F", "F", 15)
file.SetColWidth("Sheet1", "G", "G", 15)
endRow := fmt.Sprintf("H"+"%d", nExcelStartRow+2)
// 应用样式到整个表格
_ = file.SetCellStyle("Sheet1", "A1", endRow, style)
endRow1 := fmt.Sprintf("E%d", nExcelStartRow+2)
_ = file.SetCellStyle("Sheet1", "E2", endRow1, style1)
fmt.Println("save fileName:", config.ExportConfig.Path+fileName)
if err := file.SaveAs(config.ExportConfig.Path + fileName); err != nil {
fmt.Println(err)
}
return url + fileName, nil
}
// 反序列化 StoreData
@ -435,6 +604,13 @@ func (e *SysUser) Update(begin *gorm.DB, id int) (update SysUser, err error) {
if err = begin.Table(e.TableName()).Model(&update).Updates(&e).Error; err != nil {
return
}
if e.Uid == 0 {
if err = begin.Table(e.TableName()).Model(&update).UpdateColumn("uid", 0).Error; err != nil {
return
}
}
return
}
@ -472,6 +648,13 @@ func GetUserById(id uint32) *SysUserB {
return u
}
func GetSysUserById(id uint32) *SysUser {
var u = new(SysUser)
orm.Eloquent.Table("sys_user").Where("user_id", id).First(u)
return u
}
// UpdateUserType 更新uid的user_type为2
func UpdateUserType(begin *gorm.DB, uid, nType, roleId uint32) error {
// 更新库存表
@ -596,3 +779,137 @@ func GetUserEffectiveStoreById(id uint32) ([]StoreInfo, error) {
return validStores, nil
}
// AddShopperCode 添加店员兑换码
func AddShopperCode(req InsertSysUserReq, begin *gorm.DB) error {
// 获取有效门店id
now := time.Now()
// 过滤掉过期的门店
validStores := make([]StoreInfo, 0)
for _, store := range req.StoreList {
expireTime, err := time.Parse(StoreDateTimeFormat, store.ExpireTime)
if err != nil {
log.Println("Error parsing time:", err, "ExpireTime:", store.ExpireTime)
continue
}
// 包含当天有效时间
expireTime = expireTime.Add(24*time.Hour - time.Second)
if expireTime.After(now) {
validStores = append(validStores, store)
}
}
if len(validStores) == 0 {
return errors.New("设置兑换码失败,无有效门店")
}
// 按有效时间和 store_id 排序
sort.Slice(validStores, func(i, j int) bool {
timeI, _ := time.Parse(StoreDateTimeFormat, validStores[i].ExpireTime)
timeJ, _ := time.Parse(StoreDateTimeFormat, validStores[j].ExpireTime)
if timeI.Equal(timeJ) {
return validStores[i].StoreID < validStores[j].StoreID
}
return timeI.Before(timeJ)
})
var shopperCode ShopperPromotionCode
shopperCode.Code = req.ShopperCode
shopperCode.Uid = req.Uid
shopperCode.State = 2
shopperCode.StoreId = uint32(validStores[0].StoreID)
if err := begin.Table("shopper_promotion_code").Create(&shopperCode).Error; err != nil {
logger.Error("create shopper_promotion_code err:", logger.Field("err", err))
return err
}
return nil
}
// UpdateShopperCode 更新店员兑换码
func UpdateShopperCode(req InsertSysUserReq, begin *gorm.DB, sysInfo *SysUser) error {
if req.Uid == sysInfo.Uid && req.ShopperCode == sysInfo.ShopperCode { // 兑换码没变化
return nil
}
var oldShopperCode ShopperPromotionCode
orm.Eloquent.Debug().Model(&ShopperPromotionCode{}).
Where("code = ? and state = ?", req.ShopperCode, 2).Find(&oldShopperCode)
if oldShopperCode.ID != 0 && oldShopperCode.Uid != sysInfo.Uid {
return errors.New(fmt.Sprintf("[%s]与已有店员识别码重复", req.ShopperCode))
}
// 获取有效门店id
now := time.Now()
// 过滤掉过期的门店
validStores := make([]StoreInfo, 0)
for _, store := range req.StoreList {
expireTime, err := time.Parse(StoreDateTimeFormat, store.ExpireTime)
if err != nil {
log.Println("Error parsing time:", err, "ExpireTime:", store.ExpireTime)
continue
}
// 包含当天有效时间
expireTime = expireTime.Add(24*time.Hour - time.Second)
if expireTime.After(now) {
validStores = append(validStores, store)
}
}
if len(validStores) == 0 {
return errors.New("设置兑换码失败,无有效门店")
}
// 按有效时间和 store_id 排序
sort.Slice(validStores, func(i, j int) bool {
timeI, _ := time.Parse(StoreDateTimeFormat, validStores[i].ExpireTime)
timeJ, _ := time.Parse(StoreDateTimeFormat, validStores[j].ExpireTime)
if timeI.Equal(timeJ) {
return validStores[i].StoreID < validStores[j].StoreID
}
return timeI.Before(timeJ)
})
// 删除原有的兑换码
if sysInfo.Uid != 0 && sysInfo.ShopperCode != "" {
err := orm.Eloquent.Table("shopper_promotion_code").Where("uid = ?", sysInfo.Uid).Delete(&ShopperPromotionCode{}).Error
if err != nil {
logger.Error("delete shopper_promotion_code err:", logger.Field("err", err))
return err
}
}
// 删除新配置的uid的兑换码
err := orm.Eloquent.Table("shopper_promotion_code").Where("uid = ?", req.Uid).Delete(&ShopperPromotionCode{}).Error
if err != nil {
logger.Error("delete shopper_promotion_code err:", logger.Field("err", err))
return err
}
// 添加新的兑换码
var shopperCode ShopperPromotionCode
shopperCode.Code = req.ShopperCode
shopperCode.Uid = req.Uid
shopperCode.State = 2
shopperCode.StoreId = uint32(validStores[0].StoreID)
if err := begin.Table("shopper_promotion_code").Create(&shopperCode).Error; err != nil {
logger.Error("create shopper_promotion_code err:", logger.Field("err", err))
return err
}
return nil
}
// IsShopperCodeExists 查询兑换码是否重复
func IsShopperCodeExists(code string) bool {
var count int64
orm.Eloquent.Debug().Model(&ShopperPromotionCode{}).
Where("code = ? and state = ?", code, 2).
Count(&count)
return count > 0
}

View File

@ -133,6 +133,8 @@ const StoreDateTimeFormat = "2006.01.02"
const (
ExportUrl = "https://admin.deovo.com/load/export/"
//ExportUrl = "https://dev.admin.deovo.com/load/export/" // dev环境
//ExportUrl = "/Users/max/Documents/" // 本地环境
)
type UserInvite struct {

View File

@ -26,7 +26,7 @@ func registerUserManageUnAuthRouter(v1 *gin.RouterGroup) {
userInfo.POST("/add_assistant", usermanage.UserAddAssistant)
userInfo.POST("/assistant_del", usermanage.UserAssistantDel)
userInfo.POST("/invite_list", usermanage.UserInviteList)
userInfo.POST("/cancel_members", usermanage.CancelMembers)
userInfo.POST("/cancel_members", usermanage.CancelMembers) // 取消租卡会员
userInfo.POST("/user_derive", usermanage.ExportDataUserMember)
userInfo.POST("/deposit_refund/list", usermanage.UserDepositRefundRecordList) // 保证金审核列表

View File

@ -290,7 +290,7 @@ func _1599190683670Test(db *gorm.DB, version string) error {
}
list8 := []models.SysUser{
{SysUserId: models.SysUserId{1}, LoginM: models.LoginM{models.UserName{"admin"}, models.PassWord{"$2a$10$cKFFTCzGOvaIHHJY2K45Zuwt8TD6oPzYi4s5MzYIBAWCLL6ZhouP2"}}, SysUserB: models.SysUserB{"zhangwj", "13818888888", 1, "", "", "0", "1@qq.com", 1, 1, "1", "1", "", "0", 1, "总店", 1, "迪为", 1, "", []models.StoreInfo{{1, "", ""}}, 0, 0, models.BaseModel{CreatedAt: time.Now(), UpdatedAt: time.Now()}, "", ""}},
{SysUserId: models.SysUserId{1}, LoginM: models.LoginM{models.UserName{"admin"}, models.PassWord{"$2a$10$cKFFTCzGOvaIHHJY2K45Zuwt8TD6oPzYi4s5MzYIBAWCLL6ZhouP2"}}, SysUserB: models.SysUserB{"zhangwj", "13818888888", 1, "", "", "0", "1@qq.com", 1, 1, "1", "1", "", "0", 1, "总店", 1, "迪为", 1, "", []models.StoreInfo{{1, "", ""}}, 0, 0, "", models.BaseModel{CreatedAt: time.Now(), UpdatedAt: time.Now()}, "", ""}},
}
list9 := []models.DictData{

View File

@ -0,0 +1,3 @@
-----BEGIN RSA PUBLIC KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCZqJtyqYd4HcYPNQnR2/IDDgcUFXjWs0kDMIre7AF6zNAcFD/vTOCcEzmb0scLhduoy6sEXj6lxdAuNYXKhVJIh2XRdORVMLqtdgeGN3W5rohQSC/8kWt6VmcXJZQw5YDdbSpacSa0djLxX8+lJuQwrkkNQKb41/uGifCwvnpF9sR8DqF9iDQn3LNoV2AkkCmXfXCPh2GJD1DOXes81dxzqWAc1kCSyGIPNgWgspV7rU4Zm5VpnomptxvMnIr3F+HXxM4zVk48JHwA6+FwQaw/G/XdqiZTwFtm65VbEEYrmsj8UYlxzeNOa6xv20AsmhwYJIMAi3Q+ziH1pVDGN1+3AgMBAAECggEAReUnSKIK6D2K4VH79IT68h7IY39c5zTIanYDRWHPTn+pzov7hSvQI86u7s2TEw/BmmeClEsWbiusBcj84eGBS1KjowJr9sBiuhKtW4UQvPTCNtqPUXEIla6F2EaUwSU0WASXNmqv83istZUii/pD5EzzF98n1JvSYyGN5afPUNE3liMI+xsM1WdVuzB+hewLBS/98cFBDcrHbakxjFiBYiyuo3vwvu4JpmtoLlMB/J9cDNFi2Xu12kk2x1wEFvpErDd8fZrQny/Qvj9tt8O+GZSPQqHFHxooRRubCkI6UWz3Qlx0GW3H5mRFYz1bqi4SD7BfTiS/LnmIU0UwSjrwsQKBgQDmhT6MPBUfNCREBvYyDu1qaRwRpXH78PvZKPgeaTzZqf8f9+2B97/xEQ1BZoDgjK3RG6CIrHmqjW1+uAFtsU/DvfSq49HlPV2Fdqt16vAeYIU2dnWCkNyl5eWlfxOLwWVqclsiHwHY9RZbmrg7/yW3oUqCF+9Gmd49Oogg4cDQLwKBgQCqpH820p6uRtqcphpYQPrws/L+zlX8Ddh2EiBcPZvu1VOCr9CEdhDguoP6Igk9d+eMnqXW6fczXtS88YuRNiqrg7hynWKtP4XPj6bTUMA9IK5Aum9NdWt7UmT9b+3iV0Dp28/TLIy0jOht0cFpkJTpNfypmIO+h5INPVIkFva++QKBgQClbkoM6bFey1SbXUOheQT4sKXsJAdA/xg+KCCn8m4w5saocoyIEPw2TD5vCNjETTEQN/tlGiHWO9iwb+zWg8DygIfte8FN+lP7S8aQwSHBKxNummSKZttyUyITOrcUPJ5DXf345re0s25wHwDITbsLpTyLUBHvYM0Us8StlFWDEQKBgAxJgfuBmPl1kqI696SpMSiJ3JJqaxiWKqL91SSvLv44kCXV4Q7YrYhxBbXKI54wdxTSC6D5AdrKFklwnxsaqmHlPy/Jk2RkMY9riZintN/x7XotsnwCW3XqzejN2XQ10i/EqydKiuspRkc6FlIynfZY89OGbt4WRvb7FmIQ4T2JAoGBAIVfna3AOKOngLHyjsBMRtpXsipV3rYKatuW5jMPP2WsJRAdn/I5VNxYDB4Su5/ieHjKE49cESeMsZbBB5myO4nUiLiZj3Pmvz7rmlTlGXtOS9anT6vYvWnKk8QSQJAWowE8AIHfN5m4pmZqRo4Es4gQvQt+vNavYEHt/+qWgn4m
-----END RSA PUBLIC KEY-----

View File

@ -0,0 +1,3 @@
-----BEGIN RSA PUBLIC KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCZqJtyqYd4HcYPNQnR2/IDDgcUFXjWs0kDMIre7AF6zNAcFD/vTOCcEzmb0scLhduoy6sEXj6lxdAuNYXKhVJIh2XRdORVMLqtdgeGN3W5rohQSC/8kWt6VmcXJZQw5YDdbSpacSa0djLxX8+lJuQwrkkNQKb41/uGifCwvnpF9sR8DqF9iDQn3LNoV2AkkCmXfXCPh2GJD1DOXes81dxzqWAc1kCSyGIPNgWgspV7rU4Zm5VpnomptxvMnIr3F+HXxM4zVk48JHwA6+FwQaw/G/XdqiZTwFtm65VbEEYrmsj8UYlxzeNOa6xv20AsmhwYJIMAi3Q+ziH1pVDGN1+3AgMBAAECggEAReUnSKIK6D2K4VH79IT68h7IY39c5zTIanYDRWHPTn+pzov7hSvQI86u7s2TEw/BmmeClEsWbiusBcj84eGBS1KjowJr9sBiuhKtW4UQvPTCNtqPUXEIla6F2EaUwSU0WASXNmqv83istZUii/pD5EzzF98n1JvSYyGN5afPUNE3liMI+xsM1WdVuzB+hewLBS/98cFBDcrHbakxjFiBYiyuo3vwvu4JpmtoLlMB/J9cDNFi2Xu12kk2x1wEFvpErDd8fZrQny/Qvj9tt8O+GZSPQqHFHxooRRubCkI6UWz3Qlx0GW3H5mRFYz1bqi4SD7BfTiS/LnmIU0UwSjrwsQKBgQDmhT6MPBUfNCREBvYyDu1qaRwRpXH78PvZKPgeaTzZqf8f9+2B97/xEQ1BZoDgjK3RG6CIrHmqjW1+uAFtsU/DvfSq49HlPV2Fdqt16vAeYIU2dnWCkNyl5eWlfxOLwWVqclsiHwHY9RZbmrg7/yW3oUqCF+9Gmd49Oogg4cDQLwKBgQCqpH820p6uRtqcphpYQPrws/L+zlX8Ddh2EiBcPZvu1VOCr9CEdhDguoP6Igk9d+eMnqXW6fczXtS88YuRNiqrg7hynWKtP4XPj6bTUMA9IK5Aum9NdWt7UmT9b+3iV0Dp28/TLIy0jOht0cFpkJTpNfypmIO+h5INPVIkFva++QKBgQClbkoM6bFey1SbXUOheQT4sKXsJAdA/xg+KCCn8m4w5saocoyIEPw2TD5vCNjETTEQN/tlGiHWO9iwb+zWg8DygIfte8FN+lP7S8aQwSHBKxNummSKZttyUyITOrcUPJ5DXf345re0s25wHwDITbsLpTyLUBHvYM0Us8StlFWDEQKBgAxJgfuBmPl1kqI696SpMSiJ3JJqaxiWKqL91SSvLv44kCXV4Q7YrYhxBbXKI54wdxTSC6D5AdrKFklwnxsaqmHlPy/Jk2RkMY9riZintN/x7XotsnwCW3XqzejN2XQ10i/EqydKiuspRkc6FlIynfZY89OGbt4WRvb7FmIQ4T2JAoGBAIVfna3AOKOngLHyjsBMRtpXsipV3rYKatuW5jMPP2WsJRAdn/I5VNxYDB4Su5/ieHjKE49cESeMsZbBB5myO4nUiLiZj3Pmvz7rmlTlGXtOS9anT6vYvWnKk8QSQJAWowE8AIHfN5m4pmZqRo4Es4gQvQt+vNavYEHt/+qWgn4m
-----END RSA PUBLIC KEY-----

View File

@ -0,0 +1,3 @@
-----BEGIN RSA PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmaibcqmHeB3GDzUJ0dvyAw4HFBV41rNJAzCK3uwBeszQHBQ/70zgnBM5m9LHC4XbqMurBF4+pcXQLjWFyoVSSIdl0XTkVTC6rXYHhjd1ua6IUEgv/JFrelZnFyWUMOWA3W0qWnEmtHYy8V/PpSbkMK5JDUCm+Nf7honwsL56RfbEfA6hfYg0J9yzaFdgJJApl31wj4dhiQ9Qzl3rPNXcc6lgHNZAkshiDzYFoLKVe61OGZuVaZ6JqbcbzJyK9xfh18TOM1ZOPCR8AOvhcEGsPxv13aomU8BbZuuVWxBGK5rI/FGJcc3jTmusb9tALJocGCSDAIt0Ps4h9aVQxjdftwIDAQAB
-----END RSA PUBLIC KEY-----

View File

@ -0,0 +1,3 @@
-----BEGIN RSA PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmaibcqmHeB3GDzUJ0dvyAw4HFBV41rNJAzCK3uwBeszQHBQ/70zgnBM5m9LHC4XbqMurBF4+pcXQLjWFyoVSSIdl0XTkVTC6rXYHhjd1ua6IUEgv/JFrelZnFyWUMOWA3W0qWnEmtHYy8V/PpSbkMK5JDUCm+Nf7honwsL56RfbEfA6hfYg0J9yzaFdgJJApl31wj4dhiQ9Qzl3rPNXcc6lgHNZAkshiDzYFoLKVe61OGZuVaZ6JqbcbzJyK9xfh18TOM1ZOPCR8AOvhcEGsPxv13aomU8BbZuuVWxBGK5rI/FGJcc3jTmusb9tALJocGCSDAIt0Ps4h9aVQxjdftwIDAQAB
-----END RSA PUBLIC KEY-----

View File

@ -0,0 +1,3 @@
-----BEGIN RSA PUBLIC KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDR19P9/7pIrtzsctlnFo9J5Yn1uucbMi+xRvaoM0tx2dwKBYS7AqdcibCHHlioqOV+xl6bU2T2LfyRcXr+cZJIl4U6UpCUfyPbBdaizlimPZwnWNEZVWQVszy2MPmGsV4f6anDakKHz80f6RZNGY1a9YEpeMea/XFQ/colQeb9mIfsfGx/sz14mL8zBwJSapngvCe0qsJf+xxtpftFUnMOKtMTF66fs8DuWQUeL3zZ0SRkNw3G/Sw1J8JUQm4Y92vMHWqDYSZnM1ExlQsf66vlRSh/BAoKZ3ezXAEppWI61Gerx6NxrONpzRyRUbtTUJIHdWbk6py9Soa8iETn6e5zAgMBAAECggEAEzvcI4DoGzdj6oxQXwGTWquebJaYDkcYVgByJVKmTKYyY/zDgLyqiHHaa1gduj/Y4TjffQ80xtfKOa6UHnRceyjgPktJE0NgDvhHBx8wwvQMtxKN/+tyxAZsvypYBL+HKBerxsybkoU6gP1FXQXFjhvInfuDGDK4yzqn56hVutKwxwbOtHzCCJQnfbV+NXKFHYA6OBIZ5LvplgeUlN0luN/b9wARSpdJSiNG9+GP8L2n7QIgFcPtLrQlhZYEnN1+USjqG4km1jdYIzSMYXuym3LCDlD4CFZgRxP8/2U2rq2kXiJRlH2l+ydNAL8dysvtgvQBLpFJJ1O+oOKWe3MyYQKBgQDv+GPvpDXwpk6alHbYRqOZVCH+XB1CBWWOsV5r84OaSRBWbgr2QE2I3V11dg8dOzd7izHpFjzItzXqjT0nTceOVDevvCco2LnDWtkC6M6o0j8NNpI4WukbzLWzOOLssAxNMVBFTqKYOJJnN6wx/s6x0RTlglCMW+d2FSOcErU1gwKBgQDf3D9zeBZF0WL8WinjF2F28C7y/yD1IZ0VTWz+fP2SlDJxyIxYdNqGl19Sqkb9+J/abPD7RXvys19Q8uSfnMXIpLh1gaokczwgwjTeaB6VwXB/5f+XPqBiO0aKe5i73VwGX2r6dsXUrtohuRp/O80qtj+ZcHmaDLYgm7/jANwAUQKBgE1jTl9HFrof9/Nz84u15CabckcET88tzF2jJ68qngNQkrs8y740aIy9ztkFlMQ5h6AI+LSRnlKgevvERrd5JuTolfjPddV/ZxDwKFH+4D6jZwAM3ETeVJTJhMNikhQAhkcSoy9mt5rdi6FL2/VXljLUGagWSYGqVc/H6272vYefAoGBAIFIuNhd/Tb7M1icVd6SDTbchbDOyWDotcisu4rJ8sQplGyELxGTAvWCDIo4TuG0KdXC3vWu7mN/VkfwzzqjFtLG1sT+Sp3cc1hT8KaVqTxByFAFK7RUddnlc9rcgJvWvqPrjWPzHlOzW8ToGzZp+hZ1xItAGupt9u0kJhDa2TPRAoGBAM2e+cEMYJc0KCHOJ/vptt7Dum/duAXrsnucREehNyZ5z3U0xaU7vFEMz5H9SI8e18kM4bgBDFkxB+enEZ6r0q9paSeZgz3hT5EtggSRa8u4MgpbVGcIQk9dbg1sT6SVUPROoL9giGL9WoRY1gDU6brHbs+EClDJUN56j28QT5xO
-----END RSA PUBLIC KEY-----

View File

@ -0,0 +1,3 @@
-----BEGIN RSA PUBLIC KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCVdPz3OdVbN/XDm0zRzGiQ3vw1eB387D2ePMP2wGcbo7zZypLvsQwa7qzz6b0+THy697VEmMOoCM7SXUv5vsqDK5dmOQK66RLhUfv/DYK5yxcZlGYwYjmnT79W0Yppu9BmtQzMeggp2+LHHCfcc39krZJvlLagLEVS1AikD9p9RcjaGFfagNNetFOjxzQP6Zdi3SsBqokAW2zcu6LH02ERaZl3fSk5F4bjrIpkFipkprJoZzXfunui0hCKO6jQrCZ56YRpFY1XlPohALS5tP4VI8cjJXrOysdIX9y88mLtD5Ts1ZYJHudkbu4/xkQzbzxyLnQtajQnaXnIFu+ML6ZJAgMBAAECggEASH/Sgl7kl3ZC2ptIHXFpu/TfJVTaPymeDldtvBHDMo4v+vogYvNgauQis8NL0J+r1cp5fQgZyTZUlYk6ZLDfbdfEforjPyX2yaRKeIPmSRgyYW8yTwAm9Xli2MuWuAmqY1gqGDqOITgP/wQydeb1AjKMmWHrYTF4g2BlvKgQFbn4JaEGScslm1CIgGWt+rt9wJ3q9A+3U2irsZGjvsFFJ/0WP00w10QQ9Faq3yfMQTQ/bF+6E63pCOm1MZbGzHzpEbvEpp/G8mMjxp+Hs+3HCra4XWdZysp5+1DUxOWFRqQ8WqyNf83OAZAph8YTHKghKt0ncX8NKF40Ws5f7UJV/QKBgQDdXTevUWF2cQpra95ab66Ba77uIn2MmwrYOdILwh2eSvjeR9H1mJPBZ2+NKMBNuYA7Tz0E8qBGborX5TuwvrWmtrWigKEU2bDFLqIATecs56MW2kB4wbCIWyQj975NrHE1NN3ip5nYQSmS2Wy/QhzSgBjJrun/udJUGW0ArjIPuwKBgQCs14QkjArHAGB1/CArG1XGuAdZBAj82o+AtEuag5JpIbC9RtlA2H9CnH3ugUhrPV192XOULd6WtujR4gv9CVdFSZXtgCeB52dj62C5LS7iH98e6QfduYvxNGljKEe87iXd62qV7gLLOi/vtoZEu8Mejqw7HQ1o6VkKLr4TI5Q3ywKBgQCJNXSEmN7eeWbJ+sySJdN2qQBpvrsvYhKwv/YwD5woN7RWoxHDN1WudZyxVGcORkLzgEQEQxeRUIeDFrWO8kbKFUo0daJiuCRXtHX51k/Kh7GRQqrfrr7rZgLawH8WyiJJpoE6MkSrxIguW9KKIkKXP4sdx+uG9Pkn47Kqz058bQKBgAk+aXnO55CnC4Gj31CO4LKFCxeOqLBlPAGFIvn7iWwH+jzVOi9GpN+6IN4NmgLqQELHy2+kWGA1HhSDg2KgCkPRYKxYC0TeTGBCqWSd7wD29WbgzaPlFX/r7qr374ZCMlJBEe080nduADxQxbONWy0aMknjDuGKgVGTGGVLpNSrAoGARHsbxf/8th/Cs/TYD8mvZgPkgFMyKZuZM4Qe6VEwZazHplWXQ0BibYxloyb/nVYABxVJ0c4noP0I7pQ2H2Y68tvNWnOmVN3NaC5t1tPhE1eAA3Nfo3S3+Ma+X1bmprSQ0nyr3UeFvR2Pl3qKj5diTo4QU8RdSi4K6SwbqaK0+Ys=
-----END RSA PUBLIC KEY-----

View File

@ -0,0 +1,3 @@
-----BEGIN RSA PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlXT89znVWzf1w5tM0cxokN78NXgd/Ow9njzD9sBnG6O82cqS77EMGu6s8+m9Pkx8uve1RJjDqAjO0l1L+b7KgyuXZjkCuukS4VH7/w2CucsXGZRmMGI5p0+/VtGKabvQZrUMzHoIKdvixxwn3HN/ZK2Sb5S2oCxFUtQIpA/afUXI2hhX2oDTXrRTo8c0D+mXYt0rAaqJAFts3Luix9NhEWmZd30pOReG46yKZBYqZKayaGc137p7otIQijuo0KwmeemEaRWNV5T6IQC0ubT+FSPHIyV6zsrHSF/cvPJi7Q+U7NWWCR7nZG7uP8ZEM288ci50LWo0J2l5yBbvjC+mSQIDAQAB
-----END RSA PUBLIC KEY-----

View File

@ -0,0 +1,3 @@
-----BEGIN RSA PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0dfT/f+6SK7c7HLZZxaPSeWJ9brnGzIvsUb2qDNLcdncCgWEuwKnXImwhx5YqKjlfsZem1Nk9i38kXF6/nGSSJeFOlKQlH8j2wXWos5Ypj2cJ1jRGVVkFbM8tjD5hrFeH+mpw2pCh8/NH+kWTRmNWvWBKXjHmv1xUP3KJUHm/ZiH7Hxsf7M9eJi/MwcCUmqZ4LwntKrCX/scbaX7RVJzDirTExeun7PA7lkFHi982dEkZDcNxv0sNSfCVEJuGPdrzB1qg2EmZzNRMZULH+ur5UUofwQKCmd3s1wBKaViOtRnq8ejcazjac0ckVG7U1CSB3Vm5OqcvUqGvIhE5+nucwIDAQAB
-----END RSA PUBLIC KEY-----

View File

@ -4589,6 +4589,39 @@ const docTemplate = `{
}
}
},
"/api/v1/order/fund_record/list": {
"post": {
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"财务管理"
],
"summary": "查询财务统计列表",
"parameters": [
{
"description": "查询财务统计列表模型",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/models.FundRecordListReq"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/models.FundRecordListResp"
}
}
}
}
},
"/api/v1/order/list": {
"post": {
"consumes": [
@ -5725,6 +5758,18 @@ const docTemplate = `{
"description": "门店id",
"name": "storeId",
"in": "query"
},
{
"type": "string",
"description": "店员兑换码",
"name": "shopper_code",
"in": "query"
},
{
"type": "string",
"description": "是否导出1-导出",
"name": "is_export",
"in": "query"
}
],
"responses": {
@ -6848,6 +6893,10 @@ const docTemplate = `{
"description": "系统生成串码2-是(系统生成) 3-否(手动添加)",
"type": "integer"
},
"img": {
"description": "图片",
"type": "string"
},
"is_imei": {
"description": "是否串码1-串码类 2-非串码",
"type": "integer"
@ -6950,6 +6999,10 @@ const docTemplate = `{
"description": "1-无串码 2-串码(系统生成) 3-串码(手动添加)",
"type": "integer"
},
"img": {
"description": "图片",
"type": "string"
},
"is_imei": {
"description": "是否串码1-串码类 2-非串码",
"type": "integer"
@ -8018,6 +8071,10 @@ const docTemplate = `{
"description": "1-无串码 2-串码(系统生成) 3-串码(手动添加)",
"type": "integer"
},
"img": {
"description": "图片",
"type": "string"
},
"is_imei": {
"description": "是否串码1-串码类 2-非串码",
"type": "integer"
@ -9627,6 +9684,14 @@ const docTemplate = `{
"description": "总员工成本:商品员工成本价之和",
"type": "number"
},
"total_employee_gross_margins": {
"description": "总员工毛利率: 员工毛利/销售/退货金额",
"type": "string"
},
"total_employee_margin": {
"description": "总员工毛利:销售金额/实际退货金额-员工成本",
"type": "number"
},
"total_gross_margins": {
"description": "销售毛利率:销售毛利/销售/退货金额",
"type": "string"
@ -10731,7 +10796,7 @@ const docTemplate = `{
"description": "入/出库,开始时间",
"type": "string"
},
"store_list": {
"store_id": {
"description": "门店复选",
"type": "array",
"items": {
@ -10922,6 +10987,13 @@ const docTemplate = `{
"description": "创建时间",
"type": "string"
},
"decision_store_id": {
"description": "门店编号列表(查询进销存的时候使用)",
"type": "array",
"items": {
"type": "integer"
}
},
"dispatch_count": {
"description": "调拨中数量(调拨中调入)",
"type": "integer"
@ -11362,6 +11434,123 @@ const docTemplate = `{
}
}
},
"models.FundRecord": {
"type": "object",
"properties": {
"amount": {
"type": "integer"
},
"createdAt": {
"description": "创建时间",
"type": "string"
},
"fund_type": {
"description": "-member_gold -member_platinum -member_black_gold",
"type": "string"
},
"id": {
"description": "数据库记录编号",
"type": "integer"
},
"out_trade_no": {
"type": "string"
},
"payment_no": {
"description": "付款单号",
"type": "string"
},
"refund_id": {
"type": "string"
},
"remark": {
"description": "备注",
"type": "string"
},
"status": {
"description": "1-待支付 2-已支付 3-已退款",
"type": "integer"
},
"transaction_id": {
"description": "支付单号",
"type": "string"
},
"uid": {
"type": "integer"
},
"updatedAt": {
"description": "更新时间",
"type": "string"
}
}
},
"models.FundRecordListReq": {
"type": "object",
"properties": {
"end_time": {
"description": "结束时间",
"type": "string"
},
"fund_type": {
"type": "string"
},
"is_export": {
"description": "1-导出",
"type": "integer"
},
"out_trade_no": {
"type": "string"
},
"pageIndex": {
"type": "integer"
},
"pageSize": {
"type": "integer"
},
"payment_no": {
"type": "string"
},
"refund_id": {
"type": "string"
},
"start_time": {
"description": "开始时间",
"type": "string"
},
"transaction_id": {
"description": "支付单号",
"type": "string"
},
"uid": {
"type": "integer"
}
}
},
"models.FundRecordListResp": {
"type": "object",
"properties": {
"export_url": {
"type": "string"
},
"list": {
"type": "array",
"items": {
"$ref": "#/definitions/models.FundRecord"
}
},
"pageIndex": {
"description": "页码",
"type": "integer"
},
"pageSize": {
"description": "每页展示条数",
"type": "integer"
},
"total": {
"description": "总条数",
"type": "integer"
}
}
},
"models.GameCard": {
"type": "object",
"properties": {
@ -11987,6 +12176,10 @@ const docTemplate = `{
"description": "性别",
"type": "string"
},
"shopper_code": {
"description": "店员兑换码",
"type": "string"
},
"status": {
"description": "状态",
"type": "string"
@ -15124,6 +15317,14 @@ const docTemplate = `{
"description": "员工成本:商品员工成本价之和",
"type": "number"
},
"employee_gross_margins": {
"description": "员工毛利率: 零售销售时:员工毛利/销售金额 零售退货时:员工毛利/退货金额",
"type": "string"
},
"employee_margin": {
"description": "员工毛利:零售销售时:销售金额-员工成本 零售退货时:实际退货金额-员工成本",
"type": "number"
},
"erp_category_id": {
"description": "分类id",
"type": "integer"
@ -16044,6 +16245,10 @@ const docTemplate = `{
"description": "性别",
"type": "string"
},
"shopper_code": {
"description": "店员兑换码",
"type": "string"
},
"status": {
"description": "状态",
"type": "string"
@ -16095,6 +16300,10 @@ const docTemplate = `{
"description": "总条数",
"type": "integer"
},
"export_url": {
"description": "导出excel路径",
"type": "string"
},
"list": {
"description": "采购报表信息",
"type": "array",
@ -16195,6 +16404,10 @@ const docTemplate = `{
"description": "性别",
"type": "string"
},
"shopper_code": {
"description": "店员兑换码",
"type": "string"
},
"status": {
"description": "状态",
"type": "string"

View File

@ -4578,6 +4578,39 @@
}
}
},
"/api/v1/order/fund_record/list": {
"post": {
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"财务管理"
],
"summary": "查询财务统计列表",
"parameters": [
{
"description": "查询财务统计列表模型",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/models.FundRecordListReq"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/models.FundRecordListResp"
}
}
}
}
},
"/api/v1/order/list": {
"post": {
"consumes": [
@ -5714,6 +5747,18 @@
"description": "门店id",
"name": "storeId",
"in": "query"
},
{
"type": "string",
"description": "店员兑换码",
"name": "shopper_code",
"in": "query"
},
{
"type": "string",
"description": "是否导出1-导出",
"name": "is_export",
"in": "query"
}
],
"responses": {
@ -6837,6 +6882,10 @@
"description": "系统生成串码2-是(系统生成) 3-否(手动添加)",
"type": "integer"
},
"img": {
"description": "图片",
"type": "string"
},
"is_imei": {
"description": "是否串码1-串码类 2-非串码",
"type": "integer"
@ -6939,6 +6988,10 @@
"description": "1-无串码 2-串码(系统生成) 3-串码(手动添加)",
"type": "integer"
},
"img": {
"description": "图片",
"type": "string"
},
"is_imei": {
"description": "是否串码1-串码类 2-非串码",
"type": "integer"
@ -8007,6 +8060,10 @@
"description": "1-无串码 2-串码(系统生成) 3-串码(手动添加)",
"type": "integer"
},
"img": {
"description": "图片",
"type": "string"
},
"is_imei": {
"description": "是否串码1-串码类 2-非串码",
"type": "integer"
@ -9616,6 +9673,14 @@
"description": "总员工成本:商品员工成本价之和",
"type": "number"
},
"total_employee_gross_margins": {
"description": "总员工毛利率: 员工毛利/销售/退货金额",
"type": "string"
},
"total_employee_margin": {
"description": "总员工毛利:销售金额/实际退货金额-员工成本",
"type": "number"
},
"total_gross_margins": {
"description": "销售毛利率:销售毛利/销售/退货金额",
"type": "string"
@ -10720,7 +10785,7 @@
"description": "入/出库,开始时间",
"type": "string"
},
"store_list": {
"store_id": {
"description": "门店复选",
"type": "array",
"items": {
@ -10911,6 +10976,13 @@
"description": "创建时间",
"type": "string"
},
"decision_store_id": {
"description": "门店编号列表(查询进销存的时候使用)",
"type": "array",
"items": {
"type": "integer"
}
},
"dispatch_count": {
"description": "调拨中数量(调拨中调入)",
"type": "integer"
@ -11351,6 +11423,123 @@
}
}
},
"models.FundRecord": {
"type": "object",
"properties": {
"amount": {
"type": "integer"
},
"createdAt": {
"description": "创建时间",
"type": "string"
},
"fund_type": {
"description": "-member_gold -member_platinum -member_black_gold",
"type": "string"
},
"id": {
"description": "数据库记录编号",
"type": "integer"
},
"out_trade_no": {
"type": "string"
},
"payment_no": {
"description": "付款单号",
"type": "string"
},
"refund_id": {
"type": "string"
},
"remark": {
"description": "备注",
"type": "string"
},
"status": {
"description": "1-待支付 2-已支付 3-已退款",
"type": "integer"
},
"transaction_id": {
"description": "支付单号",
"type": "string"
},
"uid": {
"type": "integer"
},
"updatedAt": {
"description": "更新时间",
"type": "string"
}
}
},
"models.FundRecordListReq": {
"type": "object",
"properties": {
"end_time": {
"description": "结束时间",
"type": "string"
},
"fund_type": {
"type": "string"
},
"is_export": {
"description": "1-导出",
"type": "integer"
},
"out_trade_no": {
"type": "string"
},
"pageIndex": {
"type": "integer"
},
"pageSize": {
"type": "integer"
},
"payment_no": {
"type": "string"
},
"refund_id": {
"type": "string"
},
"start_time": {
"description": "开始时间",
"type": "string"
},
"transaction_id": {
"description": "支付单号",
"type": "string"
},
"uid": {
"type": "integer"
}
}
},
"models.FundRecordListResp": {
"type": "object",
"properties": {
"export_url": {
"type": "string"
},
"list": {
"type": "array",
"items": {
"$ref": "#/definitions/models.FundRecord"
}
},
"pageIndex": {
"description": "页码",
"type": "integer"
},
"pageSize": {
"description": "每页展示条数",
"type": "integer"
},
"total": {
"description": "总条数",
"type": "integer"
}
}
},
"models.GameCard": {
"type": "object",
"properties": {
@ -11976,6 +12165,10 @@
"description": "性别",
"type": "string"
},
"shopper_code": {
"description": "店员兑换码",
"type": "string"
},
"status": {
"description": "状态",
"type": "string"
@ -15113,6 +15306,14 @@
"description": "员工成本:商品员工成本价之和",
"type": "number"
},
"employee_gross_margins": {
"description": "员工毛利率: 零售销售时:员工毛利/销售金额 零售退货时:员工毛利/退货金额",
"type": "string"
},
"employee_margin": {
"description": "员工毛利:零售销售时:销售金额-员工成本 零售退货时:实际退货金额-员工成本",
"type": "number"
},
"erp_category_id": {
"description": "分类id",
"type": "integer"
@ -16033,6 +16234,10 @@
"description": "性别",
"type": "string"
},
"shopper_code": {
"description": "店员兑换码",
"type": "string"
},
"status": {
"description": "状态",
"type": "string"
@ -16084,6 +16289,10 @@
"description": "总条数",
"type": "integer"
},
"export_url": {
"description": "导出excel路径",
"type": "string"
},
"list": {
"description": "采购报表信息",
"type": "array",
@ -16184,6 +16393,10 @@
"description": "性别",
"type": "string"
},
"shopper_code": {
"description": "店员兑换码",
"type": "string"
},
"status": {
"description": "状态",
"type": "string"

View File

@ -510,6 +510,9 @@ definitions:
imei_type:
description: 系统生成串码2-是(系统生成) 3-否(手动添加)
type: integer
img:
description: 图片
type: string
is_imei:
description: 是否串码1-串码类 2-非串码
type: integer
@ -583,6 +586,9 @@ definitions:
imei_type:
description: 1-无串码 2-串码(系统生成) 3-串码(手动添加)
type: integer
img:
description: 图片
type: string
is_imei:
description: 是否串码1-串码类 2-非串码
type: integer
@ -1369,6 +1375,9 @@ definitions:
imei_type:
description: 1-无串码 2-串码(系统生成) 3-串码(手动添加)
type: integer
img:
description: 图片
type: string
is_imei:
description: 是否串码1-串码类 2-非串码
type: integer
@ -2546,6 +2555,12 @@ definitions:
total_employee_cost:
description: 总员工成本:商品员工成本价之和
type: number
total_employee_gross_margins:
description: '总员工毛利率: 员工毛利/销售/退货金额'
type: string
total_employee_margin:
description: 总员工毛利:销售金额/实际退货金额-员工成本
type: number
total_gross_margins:
description: 销售毛利率:销售毛利/销售/退货金额
type: string
@ -3351,7 +3366,7 @@ definitions:
start_time:
description: 入/出库,开始时间
type: string
store_list:
store_id:
description: 门店复选
items:
type: integer
@ -3489,6 +3504,11 @@ definitions:
createdAt:
description: 创建时间
type: string
decision_store_id:
description: 门店编号列表(查询进销存的时候使用)
items:
type: integer
type: array
dispatch_count:
description: 调拨中数量(调拨中调入)
type: integer
@ -3811,6 +3831,88 @@ definitions:
required:
- erp_commodity_id
type: object
models.FundRecord:
properties:
amount:
type: integer
createdAt:
description: 创建时间
type: string
fund_type:
description: -member_gold -member_platinum -member_black_gold
type: string
id:
description: 数据库记录编号
type: integer
out_trade_no:
type: string
payment_no:
description: 付款单号
type: string
refund_id:
type: string
remark:
description: 备注
type: string
status:
description: 1-待支付 2-已支付 3-已退款
type: integer
transaction_id:
description: 支付单号
type: string
uid:
type: integer
updatedAt:
description: 更新时间
type: string
type: object
models.FundRecordListReq:
properties:
end_time:
description: 结束时间
type: string
fund_type:
type: string
is_export:
description: 1-导出
type: integer
out_trade_no:
type: string
pageIndex:
type: integer
pageSize:
type: integer
payment_no:
type: string
refund_id:
type: string
start_time:
description: 开始时间
type: string
transaction_id:
description: 支付单号
type: string
uid:
type: integer
type: object
models.FundRecordListResp:
properties:
export_url:
type: string
list:
items:
$ref: '#/definitions/models.FundRecord'
type: array
pageIndex:
description: 页码
type: integer
pageSize:
description: 每页展示条数
type: integer
total:
description: 总条数
type: integer
type: object
models.GameCard:
properties:
coverImg:
@ -4253,6 +4355,9 @@ definitions:
sex:
description: 性别
type: string
shopper_code:
description: 店员兑换码
type: string
status:
description: 状态
type: string
@ -6516,6 +6621,12 @@ definitions:
employee_cost:
description: 员工成本:商品员工成本价之和
type: number
employee_gross_margins:
description: '员工毛利率: 零售销售时:员工毛利/销售金额 零售退货时:员工毛利/退货金额'
type: string
employee_margin:
description: 员工毛利:零售销售时:销售金额-员工成本 零售退货时:实际退货金额-员工成本
type: number
erp_category_id:
description: 分类id
type: integer
@ -7180,6 +7291,9 @@ definitions:
sex:
description: 性别
type: string
shopper_code:
description: 店员兑换码
type: string
status:
description: 状态
type: string
@ -7217,6 +7331,9 @@ definitions:
count:
description: 总条数
type: integer
export_url:
description: 导出excel路径
type: string
list:
description: 采购报表信息
items:
@ -7290,6 +7407,9 @@ definitions:
sex:
description: 性别
type: string
shopper_code:
description: 店员兑换码
type: string
status:
description: 状态
type: string
@ -10836,6 +10956,27 @@ paths:
summary: 操作日志列表update
tags:
- system/日志
/api/v1/order/fund_record/list:
post:
consumes:
- application/json
parameters:
- description: 查询财务统计列表模型
in: body
name: request
required: true
schema:
$ref: '#/definitions/models.FundRecordListReq'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/models.FundRecordListResp'
summary: 查询财务统计列表
tags:
- 财务管理
/api/v1/order/list:
post:
consumes:
@ -11555,6 +11696,14 @@ paths:
in: query
name: storeId
type: string
- description: 店员兑换码
in: query
name: shopper_code
type: string
- description: 是否导出1-导出
in: query
name: is_export
type: string
responses:
"200":
description: OK

View File

@ -535,8 +535,10 @@ func TestMemberExpirationReminder(t *testing.T) {
func TestExpireMemberSMSSendDay(t *testing.T) {
InitIODBTest()
orm.Eloquent = IODBTest
nowTime := time.Now()
models.ExpireMemberSMSSendDay(1, nowTime)
models.ExpireMemberSMSSend()
//nowTime := time.Now()
//models.ExpireMemberSMSSendDay(1, nowTime)
}
func TestCreateInviteMemberReport(t *testing.T) {

View File

@ -6,6 +6,7 @@ import (
"gorm.io/gorm"
"log"
"math"
"reflect"
"runtime"
"strconv"
"time"
@ -134,3 +135,32 @@ func StringSliceContains(slice []string, val string) bool {
}
return false
}
// RoundFloat 保留 float64 两位小数
func RoundFloat(f float64) float64 {
return math.Round(f*100) / 100
}
// RoundFloatFields 递归处理结构体中的 float64 字段,四舍五入保留两位小数
func RoundFloatFields(v interface{}) {
val := reflect.ValueOf(v).Elem()
for i := 0; i < val.NumField(); i++ {
field := val.Field(i)
switch field.Kind() {
case reflect.Float64:
// 对 float64 类型进行四舍五入
field.SetFloat(RoundFloat(field.Float()))
case reflect.Struct:
// 递归处理子结构体
RoundFloatFields(field.Addr().Interface())
case reflect.Slice:
// 对于 slice 中的结构体,逐个处理
for j := 0; j < field.Len(); j++ {
if field.Index(j).Kind() == reflect.Struct {
RoundFloatFields(field.Index(j).Addr().Interface())
}
}
}
}
}