using DXPDAL.Party; using GB5Shared.DTO.Framework.Login; using GB5Shared.EntityHandler; using GB5Shared.GenerateAutoNumber; using GB5Shared.QueryExecutor; using GB5Shared.Resource.Response; using GB5Shared.Telemetry; using static GB5Shared.GB5Constant.Constant; namespace DXPBLL.Party; public class PartyBLL : IPartyBLL { private readonly IPartyDAL _PartyDAL; private readonly AutoNumber _AutoNumber; private readonly IQueryExecutor _QueryExecutor; private readonly BaseEntityAppService _BaseEntityAppServiceParty; private readonly BaseEntityAppService _BaseEntityAppServiceLink; private readonly BaseEntityAppService _BaseEntityAppServiceBranchLink; public PartyBLL( IPartyDAL partyDAL, AutoNumber autoNumber, IQueryExecutor queryExecutor, BaseEntityAppService baseEntityAppServiceParty, BaseEntityAppService baseEntityAppServiceLink, BaseEntityAppService baseEntityAppServiceBranchLink) { _PartyDAL = partyDAL; _AutoNumber = autoNumber; _QueryExecutor = queryExecutor; _BaseEntityAppServiceParty = baseEntityAppServiceParty; _BaseEntityAppServiceLink = baseEntityAppServiceLink; _BaseEntityAppServiceBranchLink = baseEntityAppServiceBranchLink; } // ── Reads ───────────────────────────────────────────────────────────────── public async Task GetPartyAsync(int dxpPartyId, LoginDTO login, CancellationToken ct) => await _PartyDAL.GetPartyAsync(dxpPartyId, login, ct).ConfigureAwait(false); public async Task> FindByIdentityHashAsync( string? gstinHash, string? panHash, string? mobileHash, string? emailHash, LoginDTO login, CancellationToken ct) { if (gstinHash is null && panHash is null && mobileHash is null && emailHash is null) throw new ArgumentException("At least one identity hash must be supplied for dedup lookup."); return await _PartyDAL.FindByIdentityHashAsync(gstinHash, panHash, mobileHash, emailHash, login, ct) .ConfigureAwait(false); } public async Task> GetPartyLinksAsync(int dxpPartyId, LoginDTO login, CancellationToken ct) => await _PartyDAL.GetPartyLinksAsync(dxpPartyId, login, ct).ConfigureAwait(false); public async Task> GetPartyBranchLinksAsync(int dxpPartyId, LoginDTO login, CancellationToken ct) => await _PartyDAL.GetPartyBranchLinksAsync(dxpPartyId, login, ct).ConfigureAwait(false); // ── Writes ──────────────────────────────────────────────────────────────── public async Task SavePartyAsync(PartyDTO dto, LoginDTO login, CancellationToken ct) { if (dto is null) throw new ArgumentNullException(nameof(dto)); if (string.IsNullOrWhiteSpace(dto.LegalName)) throw new ArgumentException("LegalName is required.", nameof(dto)); if (dto.PartyTypeCode is < 1 or > 5) throw new ArgumentException("PartyTypeCode must be 1-5.", nameof(dto)); bool isNew = dto.DxpPartyId == 0; var Trans = await _QueryExecutor.BeginTransactionAsync(login).ConfigureAwait(false); try { GB5Trace.Step("validate-dxp-party", new { dto.DxpPartyId, isNew }); if (isNew) { var auto = await _AutoNumber.GetNumberAsync(1, AUTONUMBERCONSTANT.DXPPARTY, login) .ConfigureAwait(false); dto.DxpPartyId = auto.StartNumber; } GB5Trace.Step("save-dxp-party", new { dto.DxpPartyId, isNew }); await _BaseEntityAppServiceParty.ExecuteSaveAsync( EntityConstant.OBJECTDXPPARTY, isNew ? EventTypeConstant.SAVEDXPPARTYEVENTTYPEID : EventTypeConstant.UPDATEDXPPARTYEVENTTYPEID, dto, login, async tx => { if (isNew) await _PartyDAL.SavePartyAsync(dto, login, tx, ct).ConfigureAwait(false); else await _PartyDAL.UpdatePartyAsync(dto, login, tx, ct).ConfigureAwait(false); return dto.DxpPartyId; }, null, -1, -1, Trans).ConfigureAwait(false); await _QueryExecutor.CommitAsync(Trans).ConfigureAwait(false); return isNew ? $"{SuccessResponse.SaveSuccessMessage} {dto.DxpPartyId}" : SuccessResponse.UpdateSuccess; } catch (Exception ex) { await _QueryExecutor.RollbackAsync(Trans).ConfigureAwait(false); GB5Trace.MarkFailed("save-dxp-party-failed", ex); throw; } } public async Task LinkPartyToTenantAsync(PartyLinkDTO dto, LoginDTO login, CancellationToken ct) { if (dto is null) throw new ArgumentNullException(nameof(dto)); if (dto.TenantId <= 0) throw new ArgumentException("TenantId is required.", nameof(dto)); if (string.IsNullOrWhiteSpace(dto.DatabaseName)) throw new ArgumentException("DatabaseName is required.", nameof(dto)); if (dto.LocalPartyId <= 0) throw new ArgumentException("LocalPartyId is required.", nameof(dto)); var Trans = await _QueryExecutor.BeginTransactionAsync(login).ConfigureAwait(false); try { GB5Trace.Step("link-dxp-party-tenant", new { dto.DxpPartyId, dto.TenantId }); var auto = await _AutoNumber.GetNumberAsync(1, AUTONUMBERCONSTANT.DXPPARTYLINK, login) .ConfigureAwait(false); dto.DxpPartyLinkId = auto.StartNumber; dto.LinkedOn = DateTime.UtcNow; dto.LinkedById = login.UserId; await _BaseEntityAppServiceLink.ExecuteSaveAsync( EntityConstant.OBJECTDXPPARTYLINK, EventTypeConstant.SAVEDXPPARTYLINKEVENTTYPEID, dto, login, async tx => { await _PartyDAL.SavePartyLinkAsync(dto, login, tx, ct).ConfigureAwait(false); return dto.DxpPartyLinkId; }, null, -1, -1, Trans).ConfigureAwait(false); await _QueryExecutor.CommitAsync(Trans).ConfigureAwait(false); return $"{SuccessResponse.SaveSuccessMessage} {dto.DxpPartyLinkId}"; } catch (Exception ex) { await _QueryExecutor.RollbackAsync(Trans).ConfigureAwait(false); GB5Trace.MarkFailed("link-dxp-party-tenant-failed", ex); throw; } } public async Task RevokePartyLinkAsync(int dxpPartyLinkId, LoginDTO login, CancellationToken ct) { var Trans = await _QueryExecutor.BeginTransactionAsync(login).ConfigureAwait(false); try { GB5Trace.Step("revoke-dxp-party-link", new { dxpPartyLinkId }); await _PartyDAL.RevokePartyLinkAsync(dxpPartyLinkId, login, Trans, ct).ConfigureAwait(false); await _QueryExecutor.CommitAsync(Trans).ConfigureAwait(false); return SuccessResponse.UpdateSuccess; } catch (Exception ex) { await _QueryExecutor.RollbackAsync(Trans).ConfigureAwait(false); GB5Trace.MarkFailed("revoke-dxp-party-link-failed", ex); throw; } } public async Task LinkPartyBranchAsync(PartyBranchLinkDTO dto, LoginDTO login, CancellationToken ct) { if (dto is null) throw new ArgumentNullException(nameof(dto)); if (dto.TenantId <= 0) throw new ArgumentException("TenantId is required.", nameof(dto)); if (dto.LocalPartyBranchId <= 0) throw new ArgumentException("LocalPartyBranchId is required.", nameof(dto)); var Trans = await _QueryExecutor.BeginTransactionAsync(login).ConfigureAwait(false); try { GB5Trace.Step("link-dxp-party-branch", new { dto.DxpPartyId, dto.LocalPartyBranchId }); var auto = await _AutoNumber.GetNumberAsync(1, AUTONUMBERCONSTANT.DXPPARTYBRANCHLINK, login) .ConfigureAwait(false); dto.DxpPartyBranchLinkId = auto.StartNumber; await _BaseEntityAppServiceBranchLink.ExecuteSaveAsync( EntityConstant.OBJECTDXPPARTYBRANCHLINK, EventTypeConstant.SAVEDXPPARTYBRANCHLINKEVENTTYPEID, dto, login, async tx => { await _PartyDAL.SavePartyBranchLinkAsync(dto, login, tx, ct).ConfigureAwait(false); return dto.DxpPartyBranchLinkId; }, null, -1, -1, Trans).ConfigureAwait(false); await _QueryExecutor.CommitAsync(Trans).ConfigureAwait(false); return $"{SuccessResponse.SaveSuccessMessage} {dto.DxpPartyBranchLinkId}"; } catch (Exception ex) { await _QueryExecutor.RollbackAsync(Trans).ConfigureAwait(false); GB5Trace.MarkFailed("link-dxp-party-branch-failed", ex); throw; } } }