cjy 2 weeks ago
commit 1b8826aa6c

@ -92,5 +92,11 @@ namespace DS.WMS.Core.Application.Entity
/// </summary>
[SugarColumn(ColumnDescription = "类别", IsNullable = true)]
public DetailCategory Category { get; set; }
/// <summary>
/// 币别
/// </summary>
[SugarColumn(ColumnDescription = "币别", IsNullable = false, Length = 3)]
public string Currency { get; set; }
}
}

@ -653,6 +653,7 @@ namespace DS.WMS.Core.Application.Method
ApplicationId = application.Id,
CodeId = code.Id,
Name = code.Name,
Currency = code.DefaultCurrency ?? string.Empty,
Quantity = 1,
TaxUnitPrice = detail.ApplyAmount,
TaxRate = code.TaxRate,

@ -36,5 +36,12 @@ namespace DS.WMS.Core.Invoice.Interface
/// <returns></returns>
/// <exception cref="ArgumentNullException">当<paramref name="tenant"/>为null时引发。</exception>
Task<string> AddTenantAsync(Tenant tenant);
/// <summary>
/// 发送邮件
/// </summary>
/// <param name="id">发票ID</param>
/// <returns></returns>
Task<DataResult> SendMailAsync(long id);
}
}

@ -132,7 +132,8 @@ namespace DS.WMS.Core.Invoice.Method
var list = invoice.Details?.Where(x => x.DetailId.HasValue).Select(x => new ApplicationDetail
{
Id = x.DetailId.GetValueOrDefault(),
ProcessedAmount = x.ApplyAmount,
ProcessedAmount = x.Currency == x.OriginalCurrency ?
x.ApplyAmount : x.ApplyAmount / (x.ExchangeRate ?? 1),
OriginalProcessedAmount = x.OriginalAmount
}).ToList();
@ -148,54 +149,32 @@ namespace DS.WMS.Core.Invoice.Method
protected override async Task OnDeleteDetailAsync(List<Entity.Invoice> invoices, DeleteOption deleteOption)
{
var list = invoices.SelectMany(x => x.Details).Where(x => x.DetailId.HasValue).Select(x => new ApplicationDetail
{
Id = x.DetailId.GetValueOrDefault(),
ProcessedAmount = x.ApplyAmount,
OriginalProcessedAmount = x.OriginalAmount
}).ToList();
//恢复发票申请费用明细的已处理金额
await TenantDb.Updateable(list)
.PublicSetColumns(x => x.ProcessedAmount, "-").PublicSetColumns(x => x.OriginalProcessedAmount, "-")
.UpdateColumns(x => new { x.ProcessedAmount, x.OriginalProcessedAmount })
.ExecuteCommandAsync();
//还原发票申请状态
var ids = list.Where(x => x.DetailId.HasValue).Select(x => x.DetailId).Distinct();
var details = TenantDb.Queryable<ApplicationDetail>().Where(x => ids.Contains(x.Id))
var items = invoices.SelectMany(x => x.Details);
var ids = items.Select(x => x.DetailId);
//获取发票申请明细
var details = await TenantDb.Queryable<ApplicationDetail>().Where(x => ids.Contains(x.Id))
.Select(x => new ApplicationDetail
{
Id = x.Id,
Currency = x.Currency,
ApplicationId = x.ApplicationId,
ProcessedAmount = x.ProcessedAmount,
OriginalAmount = x.OriginalAmount,
OriginalProcessedAmount = x.OriginalProcessedAmount
}).ToList();
var gpList = details.GroupBy(x => x.ApplicationId);
List<InvoiceApplication> applications = [];
foreach (var gp in gpList)
{
var processedCount = gp.Count(x => x.OriginalAmount - x.OriginalProcessedAmount == 0);
var itemCount = gp.Count();
if (itemCount == processedCount)
continue;
}).ToListAsync();
var entity = new InvoiceApplication { Id = gp.Key };
if (processedCount == 0)
{
entity.Status = InvoiceApplicationStatus.AuditPassed;
}
else if (itemCount > processedCount)
foreach (var detail in details)
{
entity.Status = InvoiceApplicationStatus.PartialInvoiced;
var item = items.FirstOrDefault(x => x.DetailId == detail.Id);
detail.ProcessedAmount -= detail.Currency == item.Currency ? item.ApplyAmount : item.OriginalAmount;
detail.OriginalProcessedAmount -= item.OriginalAmount;
}
applications.Add(entity);
}
//恢复发票申请费用明细的已处理金额
await TenantDb.Updateable(details)
.UpdateColumns(x => new { x.ProcessedAmount, x.OriginalProcessedAmount })
.ExecuteCommandAsync();
if (applications.Count > 0)
await TenantDb.Updateable(applications).UpdateColumns(x => new { x.Status }).ExecuteCommandAsync();
await base.OnDeleteDetailAsync(invoices, deleteOption);
}

@ -15,7 +15,7 @@ using SqlSugar;
namespace DS.WMS.Core.Invoice.Method
{
/// <summary>
/// 发票开服务
/// 发票开出接口服务
/// </summary>
public sealed class InvoiceIssuanceService : ApplicationServiceBase, IInvoiceIssuanceService
{
@ -167,21 +167,22 @@ namespace DS.WMS.Core.Invoice.Method
/// <returns></returns>
public async Task<DataResult> UpdateInvoiceNumberAsync(string sn)
{
var result2 = DataResult.Success;
var invResult = DataResult.Success;
var invoices = await TenantDb.Queryable<Entity.Invoice>()
.Where(x => x.SN == sn && !SqlFunc.IsNullOrEmpty(x.PDFUrl))
.Where(x => x.SN == sn && !SqlFunc.IsNullOrEmpty(x.InvoiceNO))
.Select(x => new Entity.Invoice
{
SN = x.SN,
BillNO = x.BillNO,
InvoiceNO = x.InvoiceNO,
Type = x.Type,
ApiCode = x.ApiCode,
ApiStatus = x.ApiStatus,
PDFUrl = x.PDFUrl
}).ToListAsync();
result2.Data = invoices;
invResult.Data = invoices;
if (invoices.Count > 0)
return result2;
return invResult;
var order = await TenantDb.Queryable<Entity.Invoice>().Where(x => x.SN == sn).FirstAsync();
//如果开票中所属机构为空,则取用户的orgId
@ -212,6 +213,18 @@ namespace DS.WMS.Core.Invoice.Method
if (queryResult.data.Order?.Count > 0)
{
var billNumbers = queryResult.data.Order.Select(x => x.orderNo);
//获取发票ID及类型
var list = await TenantDb.Queryable<Entity.Invoice>().Where(x => billNumbers.Contains(x.BillNO))
.Select(x => new
{
x.Id,
x.BillNO,
x.Type,
x.Mode
}).ToListAsync();
DateTime dtNow = DateTime.Now;
long userId = long.Parse(User.UserId);
foreach (var item in queryResult.data.Order)
{
var inv = new Entity.Invoice
@ -221,8 +234,18 @@ namespace DS.WMS.Core.Invoice.Method
InvoiceNO = item.fphm,
ApiCode = item.State.ToString(),
ApiStatus = item.UpMessage,
PDFUrl = item.FileUrl
PDFUrl = item.FileUrl,
IsLocked = true,
LockTime = dtNow,
LockUserId = userId
};
var storedItem = list.Find(x => x.BillNO == inv.BillNO);
if (storedItem == null)
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.EmptyData));
inv.Id = storedItem.Id;
inv.Type = storedItem.Type;
inv.Mode = storedItem.Mode;
invoices.Add(inv);
switch (item.State)
@ -242,27 +265,32 @@ namespace DS.WMS.Core.Invoice.Method
await TenantDb.Ado.BeginTranAsync();
try
{
var billNumbers = invoices.Select(x => x.BillNO);
//获取发票费用明细ID
var ids = await TenantDb.Queryable<Entity.Invoice>()
.InnerJoin<ApplicationDetail>((i, d) => i.Id == d.ApplicationId)
.Where((i, d) => billNumbers.Contains(i.BillNO) && i.Type == InvoiceType.Blue)
.Select((i, d) => d.Id).ToArrayAsync();
if (ids.Length > 0)
var redIds = invoices.Where(x => x.Type == InvoiceType.Red).Select(x => x.Id).ToList();
//开出红票时,需要删除蓝票的费用明细
if (redIds.Count > 0)
{
//获取蓝票费用明细ID
var ids = await TenantDb.Queryable<ApplicationDetail>()
.InnerJoin<Entity.Invoice>((d, i) => d.ApplicationId == i.Id)
.Where((d, i) => redIds.Contains(i.RedId.Value))
.Select((d, i) => d.Id).ToArrayAsync();
//删除蓝票费用明细
await InvoiceService.Value.DeleteDetailAsync(ids);
}
await TenantDb.Updateable(invoices).WhereColumns(x => x.BillNO)
.UpdateColumns(x => new
await TenantDb.Updateable(invoices).UpdateColumns(x => new
{
x.InvoiceNO,
x.ApiCode,
x.ApiStatus,
x.PDFUrl
x.PDFUrl,
x.IsLocked,
x.LockUserId,
x.LockTime
}).ExecuteCommandAsync();
//回写发票申请的状态
if (invoices.Exists(x => x.Mode == InvoiceMode.Applcation && x.Type == InvoiceType.Blue))
await InvoiceService.Value.RefreshApplicationStatus(invoices.Select(x => x.InvoiceNO)!);
await TenantDb.Ado.CommitTranAsync();
@ -275,8 +303,8 @@ namespace DS.WMS.Core.Invoice.Method
}
}
result2.Data = invoices;
return result2;
invResult.Data = invoices;
return invResult;
}
/// <summary>
@ -350,6 +378,7 @@ namespace DS.WMS.Core.Invoice.Method
try
{
await TenantDb.InsertNav(redInvoice).Include(x => x.Details).Include(x => x.InvoiceDetails).ExecuteCommandAsync();
blueInvoice.RedId = redInvoice.Id;
blueInvoice.IsSetRed = true;
blueInvoice.RedCode = request.chyyDm;
@ -407,6 +436,40 @@ namespace DS.WMS.Core.Invoice.Method
}
}
/// <summary>
/// 发送邮件
/// </summary>
/// <param name="id">发票ID</param>
/// <returns></returns>
public async Task<DataResult> SendMailAsync(long id)
{
var inv = await TenantDb.Queryable<Entity.Invoice>().Where(x => x.Id == id)
.Select(x => new
{
orderNo = x.BillNO,
x.SaleDeptId,
x.InvoiceNO
}).FirstAsync();
if (inv == null)
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.EmptyData));
if (!string.IsNullOrEmpty(inv.InvoiceNO))
return DataResult.Failed("发票尚未开出");
//如果开票中所属机构为空,则取用户的orgId
var userOrgId = (inv.SaleDeptId != null && inv.SaleDeptId > 0) ? inv.SaleDeptId : User.OrgId;
//接口请求key密钥
var orgauthinfo = Db.Queryable<SysOrgAuth>().Where(t => t.OrgId == userOrgId).First();
api.DefaultHeaders.Clear();
api.DefaultHeaders.Add("USER_KEY", orgauthinfo.Key);
api.DefaultHeaders.Add("USER_SECRET", orgauthinfo.Secret);
var result = await api.PostAsync<InvoiceResult<SetRedConfirmation>>(AppSetting.app(["InvoiceApi", "BaseUrl"]) + "/api/Invoice/InvoiceToEmil", inv);
if (result.Data == null || !result.Data.success)
return DataResult.Failed(result.Data == null ? "请求失败" : result.Data.msg);
return DataResult.Success;
}
/// <summary>
/// 添加租户信息
/// </summary>

@ -9,6 +9,7 @@ using DS.WMS.Core.Code.Entity;
using DS.WMS.Core.Fee.Entity;
using DS.WMS.Core.Info.Entity;
using DS.WMS.Core.Invoice.Dtos;
using DS.WMS.Core.Invoice.Entity;
using DS.WMS.Core.Invoice.Interface;
using DS.WMS.Core.Op.Entity;
using DS.WMS.Core.Sys.Entity;
@ -222,7 +223,9 @@ namespace DS.WMS.Core.Invoice.Method
dbValue = await TenantDb.Queryable<TEntity>().Select(x => new TEntity
{
Id = x.Id,
InvoiceNO = x.InvoiceNO,
IsLocked = x.IsLocked,
IsSettled = x.IsSettled,
Mode = x.Mode,
}).FirstAsync(x => x.Id == request.Invoice.Id);
}
@ -362,7 +365,7 @@ namespace DS.WMS.Core.Invoice.Method
if (app.AmountOther.HasValue)
{
result2 = AssignAmount(details2.FindAll(x => x.Currency != FeeCurrency.RMB_CODE && x.OriginalCurrency != FeeCurrency.USD_CODE), app.AmountOther.Value);
result2 = AssignAmount(details2.FindAll(x => x.Currency != FeeCurrency.RMB_CODE && x.Currency != FeeCurrency.USD_CODE), app.AmountOther.Value);
if (!result2.Succeeded)
return DataResult<TEntity>.Failed(result2.Message, result2.MultiCode);
}
@ -458,8 +461,7 @@ namespace DS.WMS.Core.Invoice.Method
}
//补充销方信息
//var org = await Db.Queryable<SysOrg>().Where(x => x.Id == User.OrgId).Select(x => new { x.OrgFullName, x.LicenseCode }).FirstAsync();
var orgId = invoice.SaleDeptId ?? User.OrgId;
var orgId = invoice.SaleDeptId.GetValueOrDefault() == 0 ? User.OrgId : invoice.SaleDeptId;
var org = await Db.Queryable<SysOrg>().LeftJoin<SysOrgAuth>((t, a) => t.Id == a.OrgId).Where((t, a) => t.Id == orgId).Select((t, a) => new { t.OrgFullName, t.LicenseCode }).FirstAsync();
if (org != null)
{
@ -477,9 +479,6 @@ namespace DS.WMS.Core.Invoice.Method
invoice.Account = orgBank.BankAccountNo;
}
//生成默认备注
//invoice.InvoiceRemark = $"购买方地址电话:" + Environment.NewLine + invoice.CustomerAddressTel + Environment.NewLine
// + "购买方开户行/账号:" + invoice.CustomerBankName + " " + invoice.CustomerAccount;
if (!string.IsNullOrEmpty(invRemark))
{
invoice.Note += Environment.NewLine + invRemark;
@ -696,6 +695,7 @@ namespace DS.WMS.Core.Invoice.Method
ApplicationId = invoice.Id,
CodeId = code.Id,
Name = code.Name,
Currency = FeeCurrency.RMB_CODE,
Quantity = 1,
TaxUnitPrice = detail.ApplyAmount,
TaxRate = code.TaxRate,
@ -765,9 +765,18 @@ namespace DS.WMS.Core.Invoice.Method
/// <returns></returns>
protected virtual DataResult EnsureSettlement(TEntity invoice, TEntity? dbValue)
{
if (dbValue != null && dbValue.IsLocked)
if (dbValue != null)
{
if (dbValue.IsLocked)
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.InvoiceIsLocked));
if (!string.IsNullOrEmpty(dbValue.InvoiceNO))
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.InvoiceIsIssued));
if (dbValue.IsSettled)
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.InvoiceIsSettled));
}
return DataResult.Success;
}
@ -947,11 +956,14 @@ namespace DS.WMS.Core.Invoice.Method
if (invoices.Any(x => x.IsLocked))
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.InvoiceIsLocked));
if (invoices.Any(x => !string.IsNullOrEmpty(x.ApiCode)))
if (invoices.Any(x => !string.IsNullOrEmpty(x.InvoiceNO)))
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.InvoiceIsIssued));
var ids = invoices.Select(x => x.Id);
if (TenantDb.Queryable<ApplicationDetail>().Any(x => ids.Contains(x.RefId.Value) && x.Category == DetailCategory.InvoiceSettlement))
//var ids = invoices.Select(x => x.Id);
//if (TenantDb.Queryable<ApplicationDetail>().Any(x => ids.Contains(x.RefId.Value) && x.Category == DetailCategory.InvoiceSettlement))
// return DataResult.FailedWithDesc(nameof(MultiLanguageConst.InvoiceIsSettled));
if (invoices.Any(x => x.IsSettled))
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.InvoiceIsSettled));
return DataResult.Success;
@ -1038,8 +1050,7 @@ namespace DS.WMS.Core.Invoice.Method
LockTime = isLocked ? dt : null,
LockUserId = isLocked ? userId : null
}).ToList();
int rows = await TenantDb.Updateable(list)
.UpdateColumns(x => new { x.IsLocked, x.LockTime, x.LockUserId }).ExecuteCommandAsync();
int rows = await TenantDb.Updateable(list).UpdateColumns(x => new { x.IsLocked, x.LockTime, x.LockUserId }).ExecuteCommandAsync();
return rows > 0 ? DataResult.Success : DataResult.FailedWithDesc(nameof(MultiLanguageConst.Operation_Failed));
}

@ -646,17 +646,16 @@ namespace DS.WMS.Core.Settlement.Method
var items = list.SelectMany(x => x.Details);
var ids = items.Select(x => x.DetailId);
//获取申请明细
var details = TenantDb.Queryable<ApplicationDetail>().Where(x => ids.Contains(x.Id))
var details = await TenantDb.Queryable<ApplicationDetail>().Where(x => ids.Contains(x.Id))
.Select(x => new ApplicationDetail
{
Id = x.Id,
Currency = x.Currency,
OriginalCurrency = x.OriginalCurrency,
ApplicationId = x.ApplicationId,
ProcessedAmount = x.ProcessedAmount,
OriginalAmount = x.OriginalAmount,
OriginalProcessedAmount = x.OriginalProcessedAmount
}).ToList();
}).ToListAsync();
foreach (var detail in details)
{

@ -137,13 +137,12 @@ namespace DS.WMS.FeeApi.Controllers
/// <param name="model">发票ID</param>
/// <returns></returns>
[HttpPost, Route("SetLock")]
public async Task<DataResult> SetLockAsync([FromBody] IdModel model)
public async Task<DataResult> SetLockAsync([FromBody] IdModel<bool> model)
{
if (!ModelState.IsValid)
return DataResult.Failed(ModelState.GetErrorMessage(), MultiLanguageConst.IllegalRequest);
bool isLocked = Convert.ToBoolean(model.Value);
return await _service.SetLockAsync(isLocked, model.Ids);
return await _service.SetLockAsync(model.Value, model.Ids);
}
/// <summary>
@ -187,6 +186,18 @@ namespace DS.WMS.FeeApi.Controllers
return await issuanceService.ReverseAsync(request);
}
/// <summary>
/// 发送开票邮件
/// </summary>
/// <param name="issuanceService"></param>
/// <param name="id">发票ID</param>
/// <returns></returns>
[HttpPost, Route("SendMail")]
public async Task<DataResult> SendMailAsync([FromServices] IInvoiceIssuanceService issuanceService, long id)
{
return await issuanceService.SendMailAsync(id);
}
/// <summary>
/// 添加租户信息
/// </summary>

Loading…
Cancel
Save