@ -1,12 +1,14 @@
using System ;
using System ;
using System.Collections.Generic ;
using System.Collections.Generic ;
using System.ComponentModel.DataAnnotations ;
using System.ComponentModel.DataAnnotations ;
using System.Data.SqlClient ;
using System.Diagnostics ;
using System.Globalization ;
using System.Globalization ;
using System.IO ;
using System.IO ;
using System.Linq ;
using System.Linq ;
using System.Linq.Dynamic.Core ;
using System.Linq.Dynamic.Core ;
using System.Reflection ;
using System.Reflection ;
using System.Threading ;
using System.Text.Json ;
using System.Threading.Tasks ;
using System.Threading.Tasks ;
using ClosedXML.Excel ;
using ClosedXML.Excel ;
using LinqToDB.Data ;
using LinqToDB.Data ;
@ -42,12 +44,11 @@ namespace Win.Sfs.SettleAccount.Entities.BQ;
[Route("api/settleaccount/[controller] / [ action ] ")]
[Route("api/settleaccount/[controller] / [ action ] ")]
public class VmiAppService : ApplicationService , IJobService , ITransientDependency
public class VmiAppService : ApplicationService , IJobService , ITransientDependency
{
{
public static SemaphoreSlim backupLock = new SemaphoreSlim ( 1 ) ;
public static object backupLock = new object ( ) ;
private readonly IConfiguration _ cfg ;
private readonly IConfiguration _ cfg ;
private readonly IServiceProvider _ serviceProvider ;
private readonly IServiceProvider _ serviceProvider ;
private readonly INormalEfCoreRepository < VmiBalance , Guid > _ balanceRepository ;
private readonly INormalEfCoreRepository < VmiBalance , Guid > _ balanceRepository ;
private readonly INormalEfCoreRepository < VmiLog , Guid > _l ogRepository ;
private readonly INormalEfCoreRepository < VmiLog , Guid > _l ogRepository ;
private readonly INormalEfCoreRepository < VmiSnapshot , Guid > _ snapshotRepository ;
private readonly IBlobContainer < MyFileContainer > _f ileContainer ;
private readonly IBlobContainer < MyFileContainer > _f ileContainer ;
private readonly IHubContext < PageHub > _ hubContext ;
private readonly IHubContext < PageHub > _ hubContext ;
private readonly ICurrentUser _ currentUser ;
private readonly ICurrentUser _ currentUser ;
@ -56,7 +57,6 @@ public class VmiAppService : ApplicationService, IJobService, ITransientDependen
IServiceProvider serviceProvider ,
IServiceProvider serviceProvider ,
INormalEfCoreRepository < VmiBalance , Guid > balanceRepository ,
INormalEfCoreRepository < VmiBalance , Guid > balanceRepository ,
INormalEfCoreRepository < VmiLog , Guid > logRepository ,
INormalEfCoreRepository < VmiLog , Guid > logRepository ,
INormalEfCoreRepository < VmiSnapshot , Guid > snapshotRepository ,
IBlobContainer < MyFileContainer > fileContainer ,
IBlobContainer < MyFileContainer > fileContainer ,
IHubContext < PageHub > hubContext ,
IHubContext < PageHub > hubContext ,
ICurrentUser currentUser )
ICurrentUser currentUser )
@ -65,7 +65,6 @@ public class VmiAppService : ApplicationService, IJobService, ITransientDependen
this . _ serviceProvider = serviceProvider ;
this . _ serviceProvider = serviceProvider ;
this . _ balanceRepository = balanceRepository ;
this . _ balanceRepository = balanceRepository ;
this . _l ogRepository = logRepository ;
this . _l ogRepository = logRepository ;
this . _ snapshotRepository = snapshotRepository ;
this . _f ileContainer = fileContainer ;
this . _f ileContainer = fileContainer ;
this . _ hubContext = hubContext ;
this . _ hubContext = hubContext ;
this . _ currentUser = currentUser ;
this . _ currentUser = currentUser ;
@ -138,6 +137,8 @@ public class VmiAppService : ApplicationService, IJobService, ITransientDependen
db . Set < VmiSnapshot > ( ) . Add ( snapshot ) ;
db . Set < VmiSnapshot > ( ) . Add ( snapshot ) ;
db . SaveChanges ( ) ;
db . SaveChanges ( ) ;
db . Database . ExecuteSqlRaw ( $"select * into {table} from Set_VmiBalance;" ) ;
db . Database . ExecuteSqlRaw ( $"select * into {table} from Set_VmiBalance;" ) ;
db . Database . ExecuteSqlRaw ( $"create clustered index IX_{table}_BillTime on {table} (BillTime)" ) ;
db . Database . ExecuteSqlRaw ( $"alter table {table} add constraint PK_{table} primary key (Id);" ) ;
snapshot . End = DateTime . Now ;
snapshot . End = DateTime . Now ;
transaction . Commit ( ) ;
transaction . Commit ( ) ;
return Task . CompletedTask ;
return Task . CompletedTask ;
@ -156,25 +157,19 @@ public class VmiAppService : ApplicationService, IJobService, ITransientDependen
/// </summary>
/// </summary>
[HttpPost("invoke")]
[HttpPost("invoke")]
[DisableValidation]
[DisableValidation]
public virtual async Task < IActionResult > VmiBackup ( )
public virtual IActionResult VmiBackup ( )
{
{
if ( backupLock . CurrentCount = = 1 )
lock ( backupLock )
{
{
return new JsonResult ( new { Code = 5 0 0 , Message = "备份程序正在运行" } ) ;
try
}
{
await backupLock . WaitAsync ( ) . ConfigureAwait ( false ) ;
Invoke ( _ serviceProvider ) . Wait ( ) ;
try
return new JsonResult ( new { Code = 2 0 0 , Message = "备份成功" } ) ;
{
}
await Invoke ( _ serviceProvider ) . ConfigureAwait ( false ) ;
catch ( Exception ex )
return new JsonResult ( new { Code = 2 0 0 , Message = "备份成功" } ) ;
{
}
return new JsonResult ( new { Code = 5 0 0 , Message = ex . Message , Data = ex . ToString ( ) } ) ;
catch ( Exception ex )
}
{
return new JsonResult ( new { Code = 5 0 0 , Message = ex . Message , Data = ex . ToString ( ) } ) ;
}
finally
{
backupLock . Release ( ) ;
}
}
}
}
@ -192,7 +187,7 @@ public class VmiAppService : ApplicationService, IJobService, ITransientDependen
}
}
/// <summary>
/// <summary>
/// 库存余额导出
/// 1.1 库存余额导出
/// </summary>
/// </summary>
[HttpPost]
[HttpPost]
public async Task < string > BalanceExport ( RequestDto input )
public async Task < string > BalanceExport ( RequestDto input )
@ -205,37 +200,111 @@ public class VmiAppService : ApplicationService, IJobService, ITransientDependen
}
}
/// <summary>
/// <summary>
/// 2.库存事务查询
/// 快照列表
/// </summary>
[HttpPost]
public async Task < List < VmiSnapshot > > Snapshot ( )
{
var connectionString = this . _ serviceProvider . GetRequiredService < IConfiguration > ( ) . GetConnectionString ( "SettleAccountService" ) ;
using var connection = new SqlConnection ( connectionString ) ;
connection . Open ( ) ;
var options = new DbContextOptionsBuilder < SettleAccountDbContext > ( ) . UseSqlServer ( connection ) . Options ;
using var db = new SettleAccountDbContext ( options ) ;
var list = db . Set < VmiSnapshot > ( ) . AsNoTracking ( ) . OrderByDescending ( o = > o . Start ) . ToList ( ) ;
return list ;
}
/// <summary>
/// 2.时点库存查询
/// </summary>
[HttpPost]
public async Task < PagedResultDto < VmiBalance > > Backup ( BackupListRequest input )
{
using var scope = this . _ serviceProvider . CreateScope ( ) ;
var db = scope . ServiceProvider . GetRequiredService < SettleAccountDbContext > ( ) ;
var name = input . Name ;
var sql = $"select * from {name}" ;
var query = db . Set < VmiBalance > ( ) . FromSqlRaw ( sql ) ;
var filters = input . Filters . ToLambda < VmiBalance > ( ) ;
if ( input . Filters . Count > 0 )
{
query = query . Where ( input . Filters . ToLambda < VmiBalance > ( ) ) ;
}
var totalCount = query . Count ( ) ;
query = string . IsNullOrEmpty ( input . Sorting ) ? query : DynamicQueryableExtensions . OrderBy ( query , input . Sorting ) ;
var entities = await query . PageBy ( input . SkipCount , input . MaxResultCount ) . ToListAsync ( ) . ConfigureAwait ( false ) ;
return new PagedResultDto < VmiBalance > ( totalCount , entities ) ;
}
/// <summary>
/// 2.1时点库存导出
/// </summary>
[HttpPost]
public async Task < string > BackupExport ( BackupListRequest input )
{
using var scope = this . _ serviceProvider . CreateScope ( ) ;
var db = scope . ServiceProvider . GetRequiredService < SettleAccountDbContext > ( ) ;
var name = input . Name ;
var sql = $"select * from {name}" ;
var query = db . Set < VmiBalance > ( ) . FromSqlRaw ( sql ) ;
var filters = input . Filters . ToLambda < VmiBalance > ( ) ;
if ( input . Filters . Count > 0 )
{
query = query . Where ( input . Filters . ToLambda < VmiBalance > ( ) ) ;
}
var totalCount = query . Count ( ) ;
query = string . IsNullOrEmpty ( input . Sorting ) ? query : DynamicQueryableExtensions . OrderBy ( query , input . Sorting ) ;
var entities = await query . ToListAsync ( ) . ConfigureAwait ( false ) ;
var fileName = $"库存快照_{input.Name}.xlsx" ;
var content = this . GetContent ( entities , "库存快照" ) ;
await _f ileContainer . SaveAsync ( fileName , content , true ) . ConfigureAwait ( false ) ;
return fileName ;
}
/// <summary>
/// 3.库存事务查询
/// </summary>
/// </summary>
/// <param name="input"></param>
/// <param name="input"></param>
/// <returns></returns>
/// <returns></returns>
[HttpPost]
[HttpPost]
public async Task < PagedResultDto < VmiLog > > Log ( LogRequestDto input )
public async Task < PagedResultDto < VmiLog > > Log ( LogRequestDto input )
{
{
using var scope = this . _ serviceProvider . CreateScope ( ) ;
//按季度计算查询需要 union 的表名
var db = scope . ServiceProvider . GetRequiredService < SettleAccountDbContext > ( ) ;
var start = DateTime . Parse ( input . Filters . FirstOrDefault ( o = > o . Column = = "changedTime" & & o . Action = = EnumFilterAction . BiggerThanOrEqual ) . Value ) ;
var start = DateTime . Parse ( input . Filters . FirstOrDefault ( o = > o . Column = = "billTime" & & o . Action = = EnumFilterAction . BiggerThanOrEqual ) . Value ) ;
var end = DateTime . Parse ( input . Filters . FirstOrDefault ( o = > o . Column = = "changedTime" & & o . Action = = EnumFilterAction . SmallThan ) . Value ) ;
var end = DateTime . Parse ( input . Filters . FirstOrDefault ( o = > o . Column = = "billTime" & & o . Action = = EnumFilterAction . BiggerThanOrEqual ) . Value ) ;
var tables = new List < string > ( ) ;
var tables = new List < string > ( ) ;
var connectionString = this . _ serviceProvider . GetRequiredService < IConfiguration > ( ) . GetConnectionString ( "SettleAccountService" ) ;
using var connection = new SqlConnection ( connectionString ) ;
connection . Open ( ) ;
for ( var time = start ; time < = end ; time = time . AddMonths ( 1 ) )
for ( var time = start ; time < = end ; time = time . AddMonths ( 1 ) )
{
{
var tableName = $"Set_VmiLog_{time.Year}_{(time.Month - 1) / 3 + 1}" ;
var tableName = $"Set_VmiLog_{time.Year}_{(time.Month - 1) / 3 + 1}" ;
if ( ! tables . Contains ( tableName ) )
if ( ! tables . Contains ( tableName ) )
{
{
tables . Add ( tableName ) ;
var command = connection . CreateCommand ( ) ;
if ( db . Database . ExecuteSqlRaw ( $"select OBJECT_ID('{tableName}', 'U')" ) = = - 1 )
command . CommandText = $"select OBJECT_ID('{tableName}', 'U')" ;
var result = command . ExecuteScalar ( ) . ToString ( ) ;
if ( result ! = string . Empty )
{
{
var tran = db . Database . BeginTransaction ( ) ;
tables . Add ( tableName ) ;
db . Database . ExecuteSqlRaw ( $"select * into {tableName} from Set_VmiLog" ) ;
}
db . Database . ExecuteSqlRaw ( $"create clustered index IX_{tableName} on {tableName} (BillTime)" ) ;
else
tran . Commit ( ) ;
{
Debug . WriteLine ( $"{tableName}不存在" ) ;
}
}
}
}
}
}
var options = new DbContextOptionsBuilder < SettleAccountDbContext > ( ) . UseSqlServer ( connection ) . Options ;
var sql = $"select * from {tables.First()}" ;
using var db = new SettleAccountDbContext ( options ) ;
tables . Skip ( 1 ) . ForEach ( o = > sql + = $" union all select * from ${o}" ) ;
var sql = string . Empty ;
var query = db . Set < VmiLog > ( ) . FromSqlRaw ( sql ) ;
if ( tables . Any ( ) )
{
//生成 union all 的 SQL使用 FromSqlRaw 查询,如果没有分表则使用原始表
sql = $"select * from {tables.First()}" ;
tables . Skip ( 1 ) . ForEach ( o = > sql + = $" union all select * from ${o}" ) ;
}
var query = string . IsNullOrEmpty ( sql ) ? db . Set < VmiLog > ( ) . AsQueryable ( ) : db . Set < VmiLog > ( ) . FromSqlRaw ( sql ) ;
var filters = input . Filters . ToLambda < VmiLog > ( ) ;
var filters = input . Filters . ToLambda < VmiLog > ( ) ;
if ( input . Filters . Count > 0 )
if ( input . Filters . Count > 0 )
{
{
@ -248,12 +317,12 @@ public class VmiAppService : ApplicationService, IJobService, ITransientDependen
}
}
/// <summary>
/// <summary>
/// 库存事务导出
/// 3.1 库存事务导出
/// </summary>
/// </summary>
[HttpPost]
[HttpPost]
public async Task < string > LogExport ( RequestDto input )
public async Task < string > LogExport ( RequestDto input )
{
{
var entities = await _l ogRepository . GetListByFilterAsync ( input . Filters ) . ConfigureAwait ( false ) ;
var entities = await _l ogRepository . GetListByFilterAsync ( input . Filters , input . Sorting , input . MaxResultCount , input . SkipCount ) . ConfigureAwait ( false ) ;
var fileName = $"库存事务_{DateTime.Now.ToString(" yyyy - MM - dd_HH : mm : ss ")}.xlsx" ;
var fileName = $"库存事务_{DateTime.Now.ToString(" yyyy - MM - dd_HH : mm : ss ")}.xlsx" ;
var content = this . GetContent ( entities , "库存事务_" ) ;
var content = this . GetContent ( entities , "库存事务_" ) ;
await _f ileContainer . SaveAsync ( fileName , content , true ) . ConfigureAwait ( false ) ;
await _f ileContainer . SaveAsync ( fileName , content , true ) . ConfigureAwait ( false ) ;
@ -280,22 +349,42 @@ public class VmiAppService : ApplicationService, IJobService, ITransientDependen
/// <param name="log"></param>
/// <param name="log"></param>
/// <returns></returns>
/// <returns></returns>
[HttpPost]
[HttpPost]
public async Task EditBalance ( VmiLog log )
public IActionResult EditBalance ( VmiLog log )
{
{
log . SetId ( GuidGenerator . Create ( ) ) ;
var connectionString = this . _ serviceProvider . GetRequiredService < IConfiguration > ( ) . GetConnectionString ( "SettleAccountService" ) ;
if ( log . ChangedQty > = decimal . Zero )
using var connection = new SqlConnection ( connectionString ) ;
connection . Open ( ) ;
using var transaction = connection . BeginTransaction ( ) ;
try
{
{
log . Qty = log . ChangedQty ;
var options = new DbContextOptionsBuilder < SettleAccountDbContext > ( ) . UseSqlServer ( connection ) . Options ;
log . LogType = VmiLogType . Type500 ;
using var db = new SettleAccountDbContext ( options ) ;
log . ChangedType = VmiType . In ;
log . SetId ( GuidGenerator . Create ( ) ) ;
if ( log . ChangedQty > = decimal . Zero )
{
log . Qty = log . ChangedQty ;
log . LogType = VmiLogType . Type500 ;
log . ChangedType = VmiType . In ;
}
else
{
log . Qty = - log . Qty ;
log . LogType = VmiLogType . Type600 ;
log . ChangedType = VmiType . Out ;
}
log . ChangedBy = this . _ currentUser . UserName ;
log . ChangedTime = DateTime . Now ;
db . Set < VmiLog > ( ) . Add ( log ) ;
db . Set < VmiMessage > ( ) . Add ( new VmiMessage ( GuidGenerator . Create ( ) ) { Message = JsonSerializer . Serialize ( log ) } ) ;
transaction . Commit ( ) ;
return new OkResult ( ) ;
}
}
else
catch ( Exc eption ex )
{
{
log . Qty = - log . Qty ;
transaction . Rollback ( ) ;
log . LogType = VmiLogType . Type600 ;
Console . WriteLine ( ex . ToString ( ) ) ;
log . ChangedType = VmiType . Out ;
return new JsonResult ( new { code = 4 0 0 , data = ex . ToString ( ) , message = ex . Message } ) ; ;
}
}
log . ChangedBy = this . _ currentUser . UserName ;
}
}
/// <summary>
/// <summary>
@ -310,67 +399,10 @@ public class VmiAppService : ApplicationService, IJobService, ITransientDependen
var list = this . ImportInternal < VmiLog > ( ms . ToArray ( ) ) ;
var list = this . ImportInternal < VmiLog > ( ms . ToArray ( ) ) ;
foreach ( var file in list )
foreach ( var file in list )
{
{
await EditBalance ( file ) . ConfigureAwait ( fals e ) ;
EditBalance ( file ) ;
}
}
}
}
/// <summary>
/// 快照列表
/// </summary>
[HttpPost]
public async Task < ListResultDto < VmiSnapshot > > Snapshot ( )
{
var list = await _ snapshotRepository . GetListAsync ( ) . ConfigureAwait ( false ) ;
return new ListResultDto < VmiSnapshot > ( list ) ;
}
/// <summary>
/// 3.时点库存查询
/// </summary>
[HttpPost]
public async Task < PagedResultDto < VmiBalance > > Backup ( BackupListRequest input )
{
using var scope = this . _ serviceProvider . CreateScope ( ) ;
var db = scope . ServiceProvider . GetRequiredService < SettleAccountDbContext > ( ) ;
var name = input . Name ;
var sql = $"select * from {name}" ;
var query = db . Set < VmiBalance > ( ) . FromSqlRaw ( sql ) ;
var filters = input . Filters . ToLambda < VmiBalance > ( ) ;
if ( input . Filters . Count > 0 )
{
query = query . Where ( input . Filters . ToLambda < VmiBalance > ( ) ) ;
}
var totalCount = query . Count ( ) ;
query = string . IsNullOrEmpty ( input . Sorting ) ? query : DynamicQueryableExtensions . OrderBy ( query , input . Sorting ) ;
var entities = await query . PageBy ( input . SkipCount , input . MaxResultCount ) . ToListAsync ( ) . ConfigureAwait ( false ) ;
return new PagedResultDto < VmiBalance > ( totalCount , entities ) ;
}
/// <summary>
/// 时点库存导出
/// </summary>
[HttpPost]
public async Task < string > BackupExport ( BackupListRequest input )
{
using var scope = this . _ serviceProvider . CreateScope ( ) ;
var db = scope . ServiceProvider . GetRequiredService < SettleAccountDbContext > ( ) ;
var name = input . Name ;
var sql = $"select * from {name}" ;
var query = db . Set < VmiBalance > ( ) . FromSqlRaw ( sql ) ;
var filters = input . Filters . ToLambda < VmiBalance > ( ) ;
if ( input . Filters . Count > 0 )
{
query = query . Where ( input . Filters . ToLambda < VmiBalance > ( ) ) ;
}
var totalCount = query . Count ( ) ;
query = string . IsNullOrEmpty ( input . Sorting ) ? query : DynamicQueryableExtensions . OrderBy ( query , input . Sorting ) ;
var entities = await query . ToListAsync ( ) . ConfigureAwait ( false ) ;
var fileName = $"库存备份_{input.Name}.xlsx" ;
var content = this . GetContent ( entities , "库存备份" ) ;
await _f ileContainer . SaveAsync ( fileName , content , true ) . ConfigureAwait ( false ) ;
return fileName ;
}
private List < T > ImportInternal < T > ( byte [ ] data )
private List < T > ImportInternal < T > ( byte [ ] data )
{
{
var list = new List < T > ( ) ;
var list = new List < T > ( ) ;