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

334 lines
14 KiB
C#

using DS.Module.Core;
using DS.Module.Core.Enums;
using DS.WMS.Core.Application.Entity;
using DS.WMS.Core.Application.Method;
using DS.WMS.Core.Code.Entity;
using DS.WMS.Core.Invoice.Dtos;
using DS.WMS.Core.Invoice.Interface;
using DS.WMS.Core.Sys.Entity;
using Masuit.Tools;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json.Linq;
using SqlSugar;
namespace DS.WMS.Core.Invoice.Method
{
/// <summary>
/// 发票开具服务
/// </summary>
public sealed class InvoiceIssuanceService : ApplicationServiceBase, IInvoiceIssuanceService
{
//readonly InvoiceApiFox api;
static readonly ApiFox api;
static InvoiceIssuanceService()
{
api = new ApiFox();
}
/// <summary>
/// 初始化并加载配置
/// </summary>
/// <param name="provider"></param>
public InvoiceIssuanceService(IServiceProvider provider) : base(provider)
{
var config = provider.GetRequiredService<IConfiguration>();
}
/// <summary>
/// 发起开票请求
/// </summary>
/// <param name="ids">发票ID</param>
/// <returns></returns>
public async Task<DataResult> InitiateAsync(params long[] ids)
{
ArgumentNullException.ThrowIfNull(ids, nameof(ids));
long userId = long.Parse(User.UserId);
var userInfo = await Db.Queryable<SysUser>().Where(x => x.Id == userId).Select(x => new
{
x.UserName,
x.IdCardNo
}).FirstAsync();
if (string.IsNullOrEmpty(userInfo.IdCardNo))
return DataResult.FailedWithDesc(MultiLanguageConst.DrawerIDNumberIsNull);
//请求参数设置
InvoiceIssuanceRequest request = new()
{
order = await TenantDb.Queryable<Entity.Invoice>().Where(x => ids.Contains(x.Id)).Select(x => new InvoiceInfo
{
invoiceType = x.Type == null ? "1" : ((int)x.Type).ToString(),
orderNo = x.BillNO,
email = x.Email,
buyerTaxNum = x.CustomerTaxID,
buyerName = x.InvoiceHeader,
buyerAddress = x.CustomerAddressTel,
buyerTel = "",
gmfkhh = x.CustomerBankName,
gmfzh = x.CustomerAccount,
skyhmc = x.BankName,
skyhzh = x.Account,
checker = x.Checker,
payee = x.Payee,
invoiceLine = x.CategoryCode,
//---------金额项---------
hjse = x.InvoiceAmount * x.TaxRate,
hjje = x.InvoiceAmount - x.InvoiceAmount * x.TaxRate,
jshj = x.InvoiceAmount,
clerk = userInfo.UserName, //开票人
kprzjhm = userInfo.IdCardNo, //证件号
kprzjlx = "201", //身份证,
remark = x.Note,
//---------发票明细---------
invoiceDetail = SqlFunc.Subqueryable<InvoiceDetail>().Where(y => y.ApplicationId == x.Id)
.LeftJoin<CodeInvoice>((y, z) => y.CodeId == z.Id).ToList((y, z) => new InvoiceDetailInfo
{
mxxh = SqlFunc.RowNumber(y.Id), //x.InvoiceDetails.IndexOf(y) + 1,
xmmc = y.Name,
spfwjc = string.Empty,
specType = y.Specification,
unit = y.Unit,
num = y.Quantity.ToString(),
price = y.TaxUnitPrice.ToString(),
taxExcludedAmount = y.Amount - y.TaxAmount,
taxRate = y.TaxRate.ToString(),
tax = y.TaxAmount,
taxIncludedAmount = y.Amount,
goodsCode = z.Code, //商品和服务税收分类合并编码
invoiceLineProperty = "00",
favouredPolicyFlag = z.PreferentialPolicyDescription
})
}).ToListAsync()
};
if (request.order.Count == 0 || request.order.Any(x => x.invoiceDetail.Count == 0))
return DataResult.FailedWithDesc(MultiLanguageConst.InvoiceIncomplete);
//var result = await api.PostAsync<InvoiceResult<string>>("/api/Invoice/services", request);
var order = await TenantDb.Queryable<Entity.Invoice>().Where(x => ids.Contains(x.Id)).FirstAsync();
//如果开票中所属机构为空,则取用户的orgId
var userOrgId = (order.SaleDeptId != null && order.SaleDeptId > 0) ? order.SaleDeptId : User.OrgId;
var orgauthinfo = Db.Queryable<SysOrg>().LeftJoin<SysOrgAuth>((t, a) => t.Id == a.OrgId)
.Where((t, a) => t.Id == userOrgId)
.Select((t, a) => new
{
a.Key,
a.Secret
}).First();
if (orgauthinfo==null)
{
//未匹配到请求密钥,请检查
return DataResult.Failed("未匹配到请求密钥,请检查");
}
api.DefaultHeaders.Add("USER_KEY", orgauthinfo.Key);
api.DefaultHeaders.Add("USER_SECRET", orgauthinfo.Secret);
var result = await api.PostAsync<InvoiceResult<string>>(AppSetting.app(new string[] { "InvoiceApi", "BaseUrl" }) + "/api/Invoice/services", request);
if (!result.Succeeded)
return DataResult.Failed(result.Message, result.MultiCode);
var invResult = result.Data;
if (invResult.success)
{
string sn = invResult.data; //开票成功返回流水号
var invoices = ids.Select(x => new Entity.Invoice { Id = x, SN = sn, ApiType = InvoiceApiType.Default }).ToList();
await TenantDb.Updateable(invoices).UpdateColumns(x => new { x.SN, x.ApiType }).ExecuteCommandAsync();
await UpdateInvoiceNumberAsync(sn);
return DataResult.Successed("开票已提交", data: sn);
}
else
{
if (invResult.code == 1)
return await InitiateAsync(ids);
return DataResult.Failed(invResult.msg);
}
}
/// <summary>
/// 更新发票号码
/// </summary>
/// <param name="sn">开票流水号</param>
/// <returns></returns>
public async Task<DataResult> UpdateInvoiceNumberAsync(string sn)
{
var result2 = DataResult.Success;
var invoices = await TenantDb.Queryable<Entity.Invoice>()
.Where(x => x.SN == sn && !SqlFunc.IsNullOrEmpty(x.PDFUrl))
.Select(x => new Entity.Invoice
{
SN = x.SN,
BillNO = x.BillNO,
InvoiceNO = x.InvoiceNO,
ApiCode = x.ApiCode,
ApiStatus = x.ApiStatus,
PDFUrl = x.PDFUrl
}).ToListAsync();
result2.Data = invoices;
if (invoices.Count > 0)
return result2;
//var result = await api.PostAsync<InvoiceResult<InvoiceQuery>>("/api/Invoice/GetInvoiceState", new { guid = sn });
//调用查询API获取发票号
var order = await TenantDb.Queryable<Entity.Invoice>().Where(x => x.SN == sn).FirstAsync();
//如果开票中所属机构为空,则取用户的orgId
var userOrgId = (order.SaleDeptId != null && order.SaleDeptId > 0) ? order.SaleDeptId : User.OrgId;
var orgauthinfo = Db.Queryable<SysOrg>().LeftJoin<SysOrgAuth>((t, a) => t.Id == a.OrgId)
.Where((t, a) => t.Id == userOrgId)
.Select((t, a) => new
{
a.Key,
a.Secret
}).First();
if (orgauthinfo == null)
{
//未匹配到请求密钥,请检查
return DataResult.Failed("未匹配到请求密钥,请检查");
}
api.DefaultHeaders.Add("USER_KEY", orgauthinfo.Key);
api.DefaultHeaders.Add("USER_SECRET", orgauthinfo.Secret);
var result = await api.PostAsync<InvoiceResult<InvoiceQuery>>(AppSetting.app(new string[] { "InvoiceApi", "BaseUrl" }) + "/api/Invoice/GetInvoiceState", new { guid = sn });
if (!result.Succeeded)
return DataResult.Failed(result.Message, result.MultiCode);
var queryResult = result.Data;
if (queryResult == null || !queryResult.success)
return DataResult.Failed(queryResult?.msg);
if (queryResult.data.Order?.Count > 0)
{
foreach (var item in queryResult.data.Order)
{
var inv = new Entity.Invoice
{
SN = sn,
BillNO = item.orderNo,
InvoiceNO = item.fphm,
ApiCode = item.State.ToString(),
ApiStatus = item.UpMessage,
PDFUrl = item.FileUrl
};
invoices.Add(inv);
if (string.IsNullOrEmpty(inv.ApiStatus))
{
switch (item.State)
{
case 1:
inv.ApiStatus = "已提交待上传";
break;
case 2:
inv.ApiStatus = "已上传待开票";
break;
case 3:
inv.ApiStatus = "开票成功";
break;
}
}
}
await TenantDb.Updateable(invoices).WhereColumns(x => x.BillNO)
.UpdateColumns(x => new
{
x.InvoiceNO,
x.ApiCode,
x.ApiStatus,
x.PDFUrl
}).ExecuteCommandAsync();
}
result2.Data = invoices;
return result2;
}
/// <summary>
/// 更新发票号码
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public async Task<DataResult> UpdateInvoiceNumberAsync(long id)
{
var model = await TenantDb.Queryable<Entity.Invoice>().Where(x => x.Id == id)
.Select(x => new { x.Id, x.SN, x.SaleDeptId, x.ApiType }).FirstAsync();
if (model == null)
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.EmptyData));
return await UpdateInvoiceNumberAsync(model.SN);
}
/// <summary>
/// 发票冲红
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
public async Task<DataResult> ReverseAsync(InvoiceReversalRequest request)
{
var invoice = await TenantDb.Queryable<Entity.Invoice>()
.WhereIF(request.InvoiceId.HasValue, x => x.Id == request.InvoiceId)
.WhereIF(!request.orderNo.IsNullOrEmpty(), x => x.BillNO == request.orderNo)
.FirstAsync();
if (invoice == null)
return DataResult.FailedWithDesc(MultiLanguageConst.EmptyData);
var req = new InvoiceReversalRequest
{
orderNo = invoice.BillNO,
chyyDm = request.chyyDm,
lrfsf = request.lrfsf,
senid = ""//待完善
};
//如果开票中所属机构为空,则取用户的orgId
var userOrgId = (invoice.SaleDeptId != null && invoice.SaleDeptId > 0) ? invoice.SaleDeptId : User.OrgId;
//接口请求key密钥
var orgauthinfo = Db.Queryable<SysOrgAuth>().Where(t => t.OrgId == userOrgId).First();
api.DefaultHeaders.Add("USER_KEY", orgauthinfo.Key);
api.DefaultHeaders.Add("USER_SECRET", orgauthinfo.Secret);
var result = await api.PostAsync<InvoiceResult<string>>(AppSetting.app(new string[] { "InvoiceApi", "BaseUrl" }) + "/api/Invoice/RedInvoicing", req);
if (!result.Succeeded)
return DataResult.Failed(result.Message, result.MultiCode);
var invResult = result.Data;
JObject? jObj = JObject.Parse(invResult.data);
if (invResult.success)
return DataResult.Failed(invResult.msg);
invoice.IsSetRed = true;
invoice.RedReason = request.Reason;
await TenantDb.Updateable(invoice).UpdateColumns(x => new { x.IsSetRed, x.RedReason }).ExecuteCommandAsync();
return DataResult.Success;
}
/// <summary>
/// 添加租户信息
/// </summary>
/// <param name="tenant">租户信息</param>
/// <returns></returns>
/// <exception cref="ArgumentNullException">当<paramref name="tenant"/>为null时引发。</exception>
public async Task<string> AddTenantAsync(Tenant tenant)
{
ArgumentNullException.ThrowIfNull(tenant, nameof(tenant));
var result = await api.PostAsync<string>("/api/Login/AddTenant", tenant);
return result.Data;
}
}
}