2025-09-04 15:34:57 +08:00

762 lines
24 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

k# 描述
1. 部署环境 Window Server
2. 开发平台 VS2015或VS2017
3. ORM SqlSugar
4. Ioc框架 Unity
5. Aop框架 Unity
6. Json框架 Newtonsoft.Json
7. 日志框架 : log4net
8. 缓存 内存或Redis
9. Api接口帮助/swagger/已按Area区域划分
## 通用操作
1. 明显能预知的异常使用BaseException抛出
```
if (workprocess.Status != (int)WorkProcessStatus.Stop) {throw new BaseException("当前进程状态不是停止");}
```
2. 写日志
```
LogHelper.Error("错误测试str");
LogHelper.Info("错误测试Exception");
```
错误日志存放在目录App_Log当异常发生的时候每一层包括仓储和服务层都会拦截到错误信息可以看到每一层具体的传参情况。看日志可以通过http请求txt文件查看到。
3.AOP事务
方法头添加[TransactionCallHandler],需要注意只拦截一个方法最外层的事务,一个方法只拦截一次。比如
```
[TransactionCallHandler]
public void RestartStopProcess(Guid workprocessId) {}
```
4、关于批量操作
在Controller层循环在Service层只写单个处理的方法。比如例子批量审核
Controller层
```
[HttpPost]
public void Audit(List<Guid> ids)
{
foreach(var id in ids) { _workProcessService.Audit(id);}
}
```
Service层
```
[TransactionCallHandler]
public void Audit(Guid id) {}
```
此种方式能保证Service运用到事务且不会出现大事务回滚的复杂情况。
5、关于事务补充
第三方不可逆操作在方法里需要写到最后一步,比如:
```
[TransactionCallHandler]
public void TransferMoney()
{
1.执行保存数据库操作,更新支付状态
2.执行微信打款操作
}
```
6、SQL注入
若对SQL注入不了解没有把握自己写的方法会不会导致SQL注入重点看下面的SQL操作demo所有的SQL请求参数都采用参数化查询的方式提交。
7、缓存
缓存放弃使用Aop方式实现因方法内部调用时会导致无法拦截。现使用缓存直接使用接口IMyCodeCacheService中的Get和Set方法比如
```
private readonly IMyCodeCacheService _myCodeCacheService;
public UserService(IMyCodeCacheService myCodeCacheService)
{
_myCodeCacheService = myCodeCacheService;
}
public string GetRegionName(Guid id)
{
var cacheKey = $"region-{id}";
var cacheValue = _myCodeCacheService.Get(cacheKey);
if(cacheValue == null)
{
//获取得到数据
var data = "广东";
_myCodeCacheService.Set(cacheKey,data,new TimeSpan(1,0,1));
return data;
}
return cacheValue.ToString();
}
```
8、Token授权
头部增加Authorization token比如
header 'Authorization: CbkmWDbwqf5BGvRUA416zYRBlAM09Py_mYGXDwoFflEqsHworu'
9、不需要授权的接口在Controller层方法添加头
```
[AllowAnonymous]
```
比如:
```
[HttpGet]
[AllowAnonymous]
public void ExportTest()
{
}
```
10、接口统一返回参数格式
```
{
"Data": null,//返回如果有数据统一放这里不管是List还是单实体
"ResultCode": 1,//如果接口没出错则返回1;返回-1则接口出错
"ErrorMessage": null//如果接口出错,这里显示出错信息
}
```
11、GenerateCode
代码自动生成,如果已存在相应的文件,除了实体外,仓储是直接跳过。
### 代码目录结构
```
├── 00-Lib -- 依赖库文件夹
├── 02-Document -- 文档文件夹
├── 03-FrameWork -- 存放第三方开源源代码
├── 04-MyCode.Project.Domain --域
│ ├── Config --配置实体
│ ├── Message --消息实体
│ │ ├── Act --操作请求实体
│ │ ├── Request --查询实体
│ │ ├── Response --响应实体
│ │ ├── Model --数据库实体
│ │ ├── Repositories --仓储接口
├── 05-MyCode.Project.GenerateCode --代码生成
├── 06-MyCode.Project.Infrastructure --基础设施层
├── 07-MyCode.Project.OutSideService --外部引用层
├── 08-MyCode.Project.Repositories --仓储实现层
├── 09-MyCode.Project.ScheduleTask --调度层
├── 10-MyCode.Project.Services --服务层
├── 11-MyCode.Project.WebApi --WEBAPI层 --
```
## SQL操作
1. Insert插入成功会自动将自递增id新的值更新到实体
```
_workProcessRepository.Add(new WorkProcess()
{
FuncType = 1,
MethodName = "",
ParameterInfo = "",
WorkProcessId = Guid.NewGuid(),
UpdateTime = DateTime.Now
});
```
2. 取单表的前n条数据单表情况多参考这里写法只返回需要的字段不要返回表中所有字段
```
return _workProcessRepository.Queryable()
.Where(p => p.Status == (int)WorkProcessStatus.RUUNING && p.SystemType == 200)
.Take(top)
.OrderBy(p => p.UpdateTime).Select(p => new { p.WorkProcessId }).ToList();
//生成Sql
exec sp_executesql N'SELECT * FROM (SELECT [WorkProcessId] AS [WorkProcessId] ,ROW_NUMBER() OVER(ORDER BY [UpdateTime] ASC) AS RowIndex FROM [WorkProcess] WITH(NOLOCK) WHERE (( [Status] = @Status0 ) AND ( [SystemType] = @Const1 ))) T WHERE RowIndex BETWEEN 1 AND 10',N'@Status0 int,@Const1 int',@Status0=1,@Const1=200
```
3. Update 更新
```
var workProcess = _workProcessRepository.SelectFirst(p => p.WorkProcessId == Guid.Parse("7BDDBBD3-B1CD-4C25-93BA-D7BF22032108"));
workProcess.Remark = "修改测试";
_workProcessRepository.Update(workProcess);
```
4. Update 更新部分字段,如果能明确更新字段,用该方法
```
_workProcessRepository.Update(
it => new WorkProcess { Remark = "测试批量修改",SystemType = 0 },
p => p.WorkProcessId ==Guid.Parse("7BDDBBD3-B1CD-4C25-93BA-D7BF22032108"));
//生成Sql
exec sp_executesql N'UPDATE [WorkProcess] SET
[Remark] = @Const0 , [SystemType] = @Const1 WHERE ( [WorkProcessId] =@constant2)',N'@Const0 nvarchar(4000),@Const1 int,@constant2 uniqueidentifier',@Const0=N'测试批量修改',@Const1=0,@constant2='7BDDBBD3-B1CD-4C25-93BA-D7BF22032108'
```
5.Sql语句查询返回列表
```
_workProcessRepository.SelectList<WorkProcess>("Select top 10 * from workprocess where systemtype=@systemtype", new { SystemType = 200 });
//生成的Sql
exec sp_executesql N'Select top 10 * from workprocess where systemtype=@systemtype',N'@SystemType int',@SystemType=200
```
6.根据一组主键Guid返回列表
```
var ids = new List<Guid>();
ids.Add(Guid.Parse("6B2E752C-CBD3-4C56-80C0-0000339F982A"));
ids.Add(Guid.Parse("E1CD8853-993C-4EFE-8863-0000FDF68054"));
_workProcessRepository.SelectList(ids);
//生成的Sql语句
SELECT [WorkProcessId],[TypePath],[MethodName],[ParameterInfo],[UpdateTime],[Remark],[Status],[ExceptionInfo],[SystemType],[FuncType] FROM [WorkProcess] WITH(NOLOCK) WHERE [WorkProcessId] IN ('6b2e752c-cbd3-4c56-80c0-0000339f982a','e1cd8853-993c-4efe-8863-0000fdf68054')
```
7.大数据插入
当需要插入非常多的数据时先将数据处理好调用Add(List)的方法速度会很快特别注意不要一个个去Add(Model),这种会非常慢;
```
var workProcessList = new List<WorkProcess>();
for (int i = 0; i < 1000; i++)
{
workProcessList.Add(new WorkProcess(){
FuncType = 1,
MethodName = "",
ParameterInfo = "",
WorkProcessId = Guid.NewGuid(),
UpdateTime = DateTime.Now
});
}
_workProcessRepository.Add(workProcessList);
```
8.大数据修改
当需要修改非常多的数据时先将数据处理好调用Update(List)的方法速度非常快特别注意不要一个个去Update(Model),这种会非常慢;另提供一个优化的方法,只批量更新需要的字段:
```
//lines为一组Guid集合这里某些情况并不需要从数据库拿数据
var workprocesses = lines.Select(line => new WorkProcess { WorkProcessId = line.WorkProcessId, TypePath = "MyCode" });
_workProcessRepository.Update(workprocesses,it => new { it.TypePath});
//生成的Sql
UPDATE S SET S.[TypePath]=T.[TypePath] FROM [WorkProcess] S INNER JOIN (
SELECT N'6b2e752c-cbd3-4c56-80c0-0000339f982a' AS [WorkProcessId],N'test201898' AS [TypePath]
UNION ALL
SELECT N'e1cd8853-993c-4efe-8863-0000fdf68054' AS [WorkProcessId],N'test201898' AS [TypePath]
) T ON S.[WorkProcessId]=T.[WorkProcessId]
```
9、使用Sql语句查询单条数据
```
_workProcessRepository.SelectFirst<WorkProcess>("Select top 1 * from workprocess")
```
带参数:
```
_sysLoginRepository.SelectList<SysLogin>("select top 10 * from SysLogin where login like '%' + @key + '%'", new { key = "k" });
```
10、使用Sql语句查询列表数据
```
_workProcessRepository.SelectList<WorkProcess>("Select top 10 * from workprocess");
```
11、IN查询
```
_workProcessRepository.Queryable().In<WorkProcess>("workprocessid", "6B2E752C-CBD3-4C56-80C0-0000339F982A", "E1CD8853-993C-4EFE-8863-0000FDF68054")
```
根据主键IN查询
```
_basCourseRepository.Queryable().In(courseIds).Select(p => new KeyValue { Text = p.Name, Value = p.Id }).ToList();
```
```
_basDataTagRepository.Queryable().In(it => it.data_id, projectIds);
```
12、Count查询
```
_workProcessRepository.Count(p => p.SystemType == 200);
```
13、分页
```
var strSql = $@"SELECT
L.LoginId,
Login,
L.Name,
Tele,
L.Editor,
L.EditTime,
L.Status,
SR.Name AS RoleName
FROM
SysLogin L WITH (nolock)
LEFT JOIN
dbo.SysLoginRole LR WITH (NOLOCK) ON L.LoginID = LR.LoginID
LEFT JOIN
dbo.SysRole SR WITH (nolock) ON LR.RoleID = SR.RoleID";
var where = new SearchCondition();
where.AddCondition("L.MerchantID",merchantId, SqlOperator.Equal,true);
//where.AddSqlCondition("L.Login like '%' + @key + '%'",
true,
new SugarParameter("key", "a"));
where.AddSqlCondition("a.nick like @key or a.true_name like @key or a.mobile like @key ",!string.IsNullOrWhiteSpace(con.KeyWord),new SqlSugar.SugarParameter("key",$"%{con.KeyWord}%"));
where.AddCondition("L.status",1,SqlOperator.Equal,true);
var whereResult = where.BuildConditionSql();
return this.SelectListPage<LoginListResp>(strSql, where, request.Page, request.PageSize, "EditTime desc");
```
14、按需读取
```
//这里只需要一个字段
var loginRole = _sysLoginRoleRepository.Queryable().Where(p => p.LoginID == loginId).Select(p => new { p.RoleID }).First();
```
15、增加支持Sql二级缓存关键字WithCache
```
var weconfig = _basWechatConfigRepository.Queryable().Where(p => p.Appid == request.AppId).Select(p => new { p.Appid, p.AppSecret,p.CompanyId }).WithCache(60).First();
```
16、支持以工作单元方式一次性执行打包的Sql带事务
```
_basMemberRepository.AddQueue(insertMember);
_basMemberMoreRepository.AddQueue(memberMore);
_basMemberRepository.SaveQueue();
//也可以用_basMemberMoreRepository.SaveQueue();
```
工作单元的此种方法唯一不足是默认mysql没有加锁如果有修改则并发会出现问题。而mysql的for update语句可以保证update该行或表数据的时候没有被其它事务占用。如果其它事务占用则会等待其它事务提交再提交。所以上面的语句可以写成
```
_basMemberMoreRepository.BeginTran();
var memberMore = _basMemberMoreRepository.Queryable().Where(p => p.Id == 2005111149137091).With(SqlWith.UpdLock).First();
_basMemberRepository.AddQueue(insertMember);
_basMemberMoreRepository.UpdateQueue(memberMore);
_basMemberRepository.SaveQueue();//内部实现try,catch风格的事务和回滚且已经处理事务嵌套
//也可以用_basMemberMoreRepository.SaveQueue();
```
17、Api缓存
```
Api缓存为在控制层使用使用例子为
[ApiCache(ServiceSecond=50)]
[HttpGet]
public DateTime GetTest(int i)
```
# 参考或引用
- https://github.com/sunkaixuan/SqlSugar
- http://jwt.io
- https://github.com/jianxuanbing/SwashbuckleEx
# 更新记录 2020-5-10
1. SqlSugar升级到最新版
2. 增加ToJson扩展
3. 日志Info和Error存放不同目录
4. Connection关闭改为按PerRequest关闭
5. 实体生成增加字段名映射
http://120.78.137.110:2343
1) 需要更换负载均衡为nginx,报表;
2改名D:\publish\LxmReportApi统一使用lxm-report-api里面的
1) StaMemberExpensesRecord波哥需要补全这个表的历史数据
2) 判断金额是否一致
select a.id,((a.total_amount - a.balance)*a.direct) '主表' ,
ROUND(b.amont,2) '明细表',create_time
from lxm_sheet a inner join
( select sales_sheet_id,
SUM( no_balance_pay_unit_price * qty * direct ) amont from
lxm_sheet_item GROUP BY sales_sheet_id )
b on a.id=b.sales_sheet_id
where (a.total_amount - a.balance)*a.direct<>ROUND(b.amont,2) ORDER BY create_time
select * from (
select a.id,((a.total_amount - a.balance)) '主表' ,
ROUND(b.amont,4) '明细表',create_time
from lxm_sheet a inner join
( select sales_sheet_id,
SUM( no_balance_pay_unit_price * qty ) amont from
lxm_sheet_item GROUP BY sales_sheet_id )
b on a.id=b.sales_sheet_id
where (a.total_amount - a.balance)*a.direct<>ROUND(b.amont,4)
) t where (t.主表 - t.明细表) > 0.01
//MSSQL那边的验证金额
select sum(TotalAmount-balance+rechargeamount) from StaMemberExpensesRecord a
where shopid='43d7c3d0-8501-19e9-b3ac-39ef10cc301a' and createtime>='2023-04-01' and a.createtime<'2023-05-01'
and sheettYPE <> 5
and flag = 100
//比对价格不一致
select a.id,a.no_balance_pay_amount,a.balance,b.pay_amount from lxm_sheet a
left join(
select sales_sheet_id,sum(no_balance_pay_amount*direct) pay_amount from lxm_sheet_item
group by sales_sheet_id
) b on a.id = b.sales_sheet_id
where shop_id='43d7c3d0-8501-19e9-b3ac-39ef10cc301a' and create_time>='2023-04-01' and create_time<'2023-05-01'
and a.no_balance_pay_amount != b.pay_amount
select sum(totalamount-balance) from StaMemberExpensesRecord a
where shopid='43d7c3d0-8501-19e9-b3ac-39ef10cc301a' and createtime>='2023-04-01' and a.createtime<'2023-05-01'
and sheettYPE <> 5 and rechargeamount = 0
and flag = 100
1465.8000
select sum(rechargeamount) from StaMemberExpensesRecord a
where shopid='43d7c3d0-8501-19e9-b3ac-39ef10cc301a' and createtime>='2023-04-01' and a.createtime<'2023-05-01'
and sheettYPE <> 5 and rechargeamount > 0
and flag = 100
### 计算业绩汇总不一致的情况
select
a.id,
a.direct * a.total_amount,b.amount from lxm_sheet a
inner join (
select
sales_sheet_id,
SUM(in_blance_amount*direct) amount
from lxm_sheet_item
GROUP BY sales_sheet_id
) b on a.id = b.sales_sheet_id
where abs(a.direct * a.total_amount - b.amount) >0.1
select * from (
select
a.id,
a.no_balance_pay_amount*direct as '主表' ,
ROUND(b.amont,2) '明细表',
-- ((a.no_balance_pay_amount)*a.direct)-ROUND(b.amont,2),
create_time
from
lxm_sheet a inner join
( select sales_sheet_id,
SUM( no_balance_pay_amount * direct ) amont from
lxm_sheet_item GROUP BY sales_sheet_id )
b on a.id=b.sales_sheet_id
where ((a.no_balance_pay_amount)*a.direct)<>ROUND(b.amont,2)
) t where ABS(t.`主表`-t.`明细表`)>1 ORDER BY create_time DESC
名词解释:
业绩:销售单+充值单加上余额MSSQL中就是明细中的CalPrice,这里没有预售单是因为预售单最终也是转成了销售单,而算业绩是以转换成销售单时间来算的。
收款:实际支付金额,预售+销售+充值,预转销的时候并不需要实际支付钱,但并不是所有销售单都是预转销订单,需要去掉余额。
CalPrice:含余额支付的单价
NcCalPrice:不含余额支付的单价
门店诊断为0有可能显示也有可能不显示如果营业中但业绩为0则显示为0
2023-6-19
update lxm_sheet_item
set has_child_node = 0
1 套装商品统计套装SKU不需要按明细统计;
barcodeId = 'c12c74cf-8bf4-667d-877f-3a01634de171'
2 赠送的不参与统计,销售。赠送的是放其它表。-可以暂时不考虑
3) 卡券不参与商品或者服务的统计,只参与业绩金额的统计
4 自定义套餐,商品需要拆,服务也需要,如果出现没有服务的情况,则不需要拆,直接套餐就是服务了 BusSalesServiceSetLog
-- 均摊价格
按吊牌价均摊最后补齐单价4为小数4舍5入小计两位小数4舍五入
5 组合商品目前下单是直接拆成明细的,所以没这个问题;
6) 服务套餐 - 经2023-6-16和阿俊确认不需要拆分到底部
如果需要统计的是分类的数据,则要统计到明细后细分的数据,条件:lxm_sheet_item.has_child_node=0(没有子节点即为所有叶子节点数据)
1) 自定义套餐旧的不动,算到服务;
### 使用天数MSSQL那边的数据
select
convert(varchar(10),a.createtime,120)
from
RpShopUseAppletData a with(nolock)
left join
bascustomer c with(nolock) on c.id = a.customerid
where UseType in (30, 31, 32, 33, 301, 302, 303) and a.ShopID = '51870d25-999f-e48f-5523-39e64165db3f' and a.createtime >= '2023-6-1' and a.createtime <= '2023-7-1'
group by convert(varchar(10),a.createtime,120)
union
SELECT
convert(varchar(10),a.createtime,120)
FROM
StaMemberExpensesRecord a with(nolock)
left join
BasCustomer c on a.CustomerId = c.ID
WHERE a.ShopId IS NOT NULL AND a.shopid='51870d25-999f-e48f-5523-39e64165db3f'
and a.createtime >= '2023-6-1' and a.createtime < '2023-7-1'
group by convert(varchar(10),a.createtime,120)
MYSQL对比两边的数据差异
select a.shop_id,a.shi_yong_tian_shu,b.usedays from rp_shop_zhenduansibiao_search a
JOIN (select shop_id, COUNT(1) usedays from lxm_use_days where create_time>='2023-07-01' GROUP BY shop_id ) b
on a.shop_id=b.shop_id where a.days='2023-07-01' and a.shi_yong_tian_shu<>b.usedays
1 在该店铺以前没有单次消费500元以上
只算当前店铺。这个以前是根据查询条件确定的时间,还是和查询时间无关的,和查询条件无关;
2这种新客老客意思是这个月只要有一笔满足那么这个月这个人所有消费都算是老客是吗还是说满足之后才算老客。
比如这个月1号我消费了100元
2号的时候我消费了600元。
3号的时候我消费了50元。
那么这个是算老客消费了750元
第一个月满足了条件的话,算是新客,下个月开始就算老客;
3 总业绩
9月 总业绩1000
分别是 :
1号A老客消费了900
2号B新客消费了300
3号C新客退了100
4号A老客退了100
检查数据
select * from
((select
a.Id,
a.direct,
a.total_amount,
a.create_time,
a.member_id,
a.shop_id,
more.is_first_more_than_500,
more.remark,
more.update_time,
more.is_old_member_500,
more.first_more_than_500_sheet_id
from
lxm_sheet a
inner join
lxm_sheet_more more on a.id = more.id
where a.shop_id='f344cd45-26ae-3ea1-0cdd-39e611e31484' and a.create_time >= '2020-8-1' and a.create_time < '2020-9-1'
)
UNION
(select
a.Id,
a.direct,
a.amount,
a.create_time,
a.member_id,
a.shop_id,
more.is_first_more_than_500,
more.remark,
more.update_time,
more.is_old_member_500,
more.first_more_than_500_sheet_id
from
lxm_recharge a
inner join
lxm_sheet_more more on a.id = more.id
where a.shop_id='f344cd45-26ae-3ea1-0cdd-39e611e31484' and a.create_time >= '2020-8-1' and a.create_time < '2020-9-1'
)) T order by T.create_time asc
select * from
select
TT.shop_id,
TT.year,
TT.`month`,
sum(case when TT.member_id is not null and TT.is_first_more_than_500 = 0 and TT.is_old_member_500 = 0 then TT.total_amount else 0 end ) ThisMonthTiYanAmount,
sum(case when TT.member_id is not null and TT.is_first_more_than_500 = 0 and TT.is_old_member_500 = 0 then 1 else 0 end ) ThisMonthTiYanQty,
sum(case when TT.is_old_member_500 = 1 then TT.total_amount else 0 end) ThisMonthOldMemberAmount,
sum(case when TT.is_old_member_500 = 1 then 1 else 0 end ) ThisMonthOldMemberQty,
sum(case when TT.is_first_more_than_500 = 1 then TT.total_amount else 0 end) ThisMonthNewMemberAmount,
sum(case when TT.is_first_more_than_500 = 1 then 1 else 0 end ) ThisMonthNewMemberQty,
sum(TT.not_member_order_qty) ThisMonthNotMemberOrderQty,
sum(case when TT.member_id is null then TT.total_amount else 0 end) ThisMonthNotMemberAmount
from (
select
T.shop_id,
T.member_id,
YEAR(T.create_time) year,
MONTH(T.create_time) month,
max(T.is_old_member_500) is_old_member_500,
max(T.is_first_more_than_500) is_first_more_than_500,
sum(T.total_amount) total_amount,
sum(T.no_balance_pay_amount) no_balance_pay_amount,
sum(case when T.member_id is NULL and T.total_amount > 0 then 1 else 0 end) not_member_order_qty
from (
(select
a.create_time,
a.shop_id,
a.member_id,
total_amount * direct total_amount,
no_balance_pay_amount * direct no_balance_pay_amount,
more.is_first_more_than_500,
more.is_old_member_500
from
lxm_sheet a
inner JOIN
lxm_sheet_more more on a.id = more.id
)
UNION
(select
a.create_time,
a.shop_id,
a.member_id,
0 total_amount,
amount no_balance_pay_amount,
more.is_first_more_than_500,
more.is_old_member_500
from
lxm_recharge a
inner JOIN
lxm_sheet_more more on a.id = more.id
)
) T
group by T.shop_id,T.member_id,YEAR(T.create_time),MONTH(T.create_time)
) TT
group by TT.shop_id,TT.`year`,TT.`month`
select a.*,more.* from lxm_sheet a
inner JOIN
lxm_sheet_more more on a.id = more.id
where a.shop_id = '0d953a13-aece-81e3-31c7-39e63b48b1f8' and a.member_id is null
select * from lxm_sheet_more
where id = '009278e2-3143-fe99-5d8d-39e7ab3cc5ee'
部署:
1) 增加表lxm_sheet_more
2) lxm_sheet和lxm_recharge增加member_id
3) 导出增加两个模板文件
MSSQL那边的业绩获取业绩只统计销售订单的业绩
SELECT SUM(record.TotalAmount+record.YuShouTotalAmount) FROM dbo.StaMemberExpensesRecord record WITH(NOLOCK)
WHERE shopid = '55de1cfa-8bd7-ead4-2ec5-39e9da7379b8'
and CreateTime >= '2023-7-1'
and CreateTime < '2023-8-1'
AND SheetType IN ( 1,4)
对应MYSQL的取业绩
select sum(total_amount*direct) from lxm_sheet
where shop_id = '55de1cfa-8bd7-ead4-2ec5-39e9da7379b8' and create_time >= '2023-7-1' and create_time < '2023-8-1' and type = 1
增加表lxm_sheet_item_package
预转销的订单的sheet.NoBalancePayAmount = 0;
###
1增加表:lxm_enum表和数据,lxm_relation,lxm_sku,lxm_service
2检查lxm_sheet_more数据进入情况
3更新订单改成20秒更新30秒内数据变化
4) 表lxm_sheet增加字段
is_porder_sorder : 1是预转销订单 0正常订单
from_type: 0= 其他; 1= 抖音; 2= 美团; 3=自然流量; 4=老顾客列表 5=1元公益、派单
is_new_member_order:1新客订单
is_first_order:1是否首单
member_mobile:会员手机
order_clerk_id:下单店员id
order_clerk_name:店员姓名
order_clerk_mobile:店员手机
5) 检查下 StaMemberExpensesRecord != 100的数据
6) 需要补充:is_new_member_orderis_first_orderclerk_id的数据。需要核对guid的新增字段是否为null值
7) lxm_shop增加字段status 1启用 0禁用
单据:
-预售单 BusPreSalesSheet
-销售单
-- BusSalesSheet -> 有可能是预转销的订单
-> 正常的订单
-退款单
销售计划的排查:
1根据订单id得到下单店员
select id,sheet,create_time,direct,order_clerk_id from lxm_sheet
where id = '845c7b9b-d1b0-47ff-8591-01a57b9f13c0'
2) 根据店员ID得到这个店员的销售计划 :
select
cPlan.id,-- 计划id
cPlan.product_id,-- 套餐id
cPlan.name,-- 套餐名
pPlan.package_id source_package_id -- 来源的套餐id
from bd_clerk_product_sales_plan cPlan
left join
lxm_product_sales_schedule pPlan on cPlan.Product_Id = pPlan.Id
where cPlan.status = 1 and cPlan.version_time = '2023-11-1 0:00:00'
and cPlan.clerk_id = '062dd030-194c-012a-df77-3a0cea5ada93'
3) 根据上面得到的套餐id得到这些套餐的所有商品关系
-- 得到套餐的所有商品
select
a.id Id,-- 套擦id
a.package_name PackageName,
sku.name ProductOrServiceName,
sku.barcode_id ProductOrServiceId,
r.data_type DataType,
sku.base_price SourcePrice,
r.qty Qty
from
lxm_relation r
inner join
lxm_product_sales_schedule a on r.main_id = a.id
left join
lxm_sku sku on r.sub_id = sku.barcode_id and r.data_type = 1
where a.status = 1 and a.id in (
--套餐id
)
4) 根据订单得到明细:
select item_id,qty,name from lxm_sheet_item
where sales_sheet_id = '845c7b9b-d1b0-47ff-8591-01a57b9f13c0'
5) 得到套餐的商品组合:
select s.package_name,r.id,sku.name from lxm_relation r
inner join
lxm_product_sales_schedule s on r.main_id = s.id
inner join
lxm_sku sku on r.sub_id = sku.barcode_id
where main_id = 2311171116200520
### 20240729
1) 增加表api_log,api_name
2) web.config修改配置