using AccountsDAL.CustomCode.Address; using AccountsDAL.CustomCode.PartyBranch; using AccountsDAL.CustomCode.PartyOU; using AccountsDAL.DTO.PartyBranch; using GB5Shared.DTO.Framework.Criteria; using GB5Shared.DTO.Framework.Login; using GB5Shared.GenerateAutoNumber; using GB5Shared.QueryExecutor; using GB5Shared.Resource.Response; using Newtonsoft.Json; using static GB5Shared.GB5Constant.Constant; namespace AccountsBLL.PartyBranch { public class PartyBranchBLL : IPartyBranchBLL { private readonly IPartyBranchDAL _partyBranchDAL; private readonly IAddressDAL _addressDAL; private readonly IPartyOUDAL _partyOUDAL; private readonly AutoNumber _autoNumber; private readonly CodeGeneration _codeGeneration; private readonly IQueryExecutor _queryExecutor; public PartyBranchBLL( IPartyBranchDAL partyBranchDAL, IAddressDAL addressDAL, IPartyOUDAL partyOUDAL, AutoNumber autoNumber, CodeGeneration codeGeneration, IQueryExecutor queryExecutor) { _partyBranchDAL = partyBranchDAL; _addressDAL = addressDAL; _partyOUDAL = partyOUDAL; _autoNumber = autoNumber; _codeGeneration = codeGeneration; _queryExecutor = queryExecutor; } public async Task GetPartyBranch(int partyBranchId, LoginDTO loginDTO) { var dto = await _partyBranchDAL.GetPartyBranch(partyBranchId, loginDTO).ConfigureAwait(false); if (dto == null) { return JsonConvert.SerializeObject(dto); } // TDS/Account enrichment — a null result means either the owning Party is itself an // account (gated in the query) or no linked MACCOUNT row exists; either way, // PartyBranchDTO's own field initializers already match GB4's fallback defaults. var tds = await _partyBranchDAL.GetPartyBranchAccountTDS(dto.PartyBranchPartyId, loginDTO).ConfigureAwait(false); if (tds != null) { dto.TDSCategoryId = tds.TDSCategoryId; dto.TDSCategoryCode = tds.TDSCategoryCode; dto.TDSCategoryName = tds.TDSCategoryName; dto.AccountIsTDSApplicable = tds.AccountIsTDSApplicable; dto.AccountIsCompany = tds.AccountIsCompany; dto.AccountTDSState = tds.AccountTDSState; } // Nested party-branch address block — a separate concept from the DefaultAddress FK, // matching GB4's PBDAL.GetAddress(-1899999839, PartyBranchId, LoginDTO). var address = await _addressDAL.FindAddress(EntityConstant.OBJECTPARTYBRANCH, partyBranchId, loginDTO).ConfigureAwait(false); if (address != null) { dto.AddressDTO = MapAddressToReport(address); } // OU-level tax overrides for every branch under this party. dto.BulkPostPartyOUDTOs = await _partyOUDAL.GetPartyOUsForParty(dto.PartyBranchPartyId, loginDTO).ConfigureAwait(false); // Configurable (MADDONFIELDS-driven) addon block — one row per branch. dto.PartyBranchAddon = await _partyBranchDAL.GetPartyBranchAddon(partyBranchId, loginDTO).ConfigureAwait(false); return JsonConvert.SerializeObject(dto); } // Mirrors PartyBLL's identical private mapper — PartyBranchDTO.AddressDTO is typed as the // richer GB5Shared.DTO.Report.AddressDTO (City/Country/State joins), while IAddressDAL.FindAddress // returns the plainer AccountsDAL.DTO.Address.AddressDTO — the two are field-compatible but not // the same type, so this is a straight property-by-property copy, not a real transformation. private static GB5Shared.DTO.Report.AddressDTO MapAddressToReport(AccountsDAL.DTO.Address.AddressDTO src) => new() { AddressId = src.AddressId, AddressObjectTypeId = src.AddressObjectTypeId, AddressObjectId = src.AddressObjectId, AddressAddressType = src.AddressAddressType, AddressAddressNature = src.AddressAddressNature, AddressLine1 = src.AddressLine1, AddressLine2 = src.AddressLine2, AddressLine3 = src.AddressLine3, AddressLine4 = src.AddressLine4, AddressLine5 = src.AddressLine5, AddressZipCode = src.AddressZipCode, CityId = src.CityId, CityCode = src.CityCode, CityName = src.CityName, CountryId = src.CountryId, CountryCode = src.CountryCode, CountryName = src.CountryName, CountryISDCode = src.CountryISDCode, AddressPhone = src.AddressPhone, AddressMobile = src.AddressMobile, AddressFax = src.AddressFax, AddressWeb = src.AddressWeb, AddressGeoCode = src.AddressGeoCode, AddressMail = src.AddressMail, AddressVATTINNumber = src.AddressVATTINNumber, AddressVATCSTNumber = src.AddressVATCSTNumber, AddressPAN = src.AddressPAN, AddressTAN = src.AddressTAN, AddressServiceTaxNumber = src.AddressServiceTaxNumber, AddressExciseDivision = src.AddressExciseDivision, AddressExciseRange = src.AddressExciseRange, AddressExciseCodeNumber = src.AddressExciseCodeNumber, AddressExciseNotification = src.AddressExciseNotification, AddressExciseCircle = src.AddressExciseCircle, AddressExciseCollectrate = src.AddressExciseCollectrate, AddressExciseRegisterNumber = src.AddressExciseRegisterNumber, AddressTDSCircle = src.AddressTDSCircle, StandardRegionId = src.StandardRegionId, StandardRegionCode = src.StandardRegionCode, StandardRegionName = src.StandardRegionName, LocationId = src.LocationId, LocationCode = src.LocationCode, LocationName = src.LocationName, AddressGSTIn = src.AddressGSTIn, StateId = src.StateId, StateCode = src.StateCode, StateName = src.StateName, StateGSTStateCode = src.StateGSTStateCode, StateTINStart = src.StateTINStart, AddressGeolocation = src.AddressGeolocation, AddressBorder = src.AddressBorder, AddressCreatedById = src.AddressCreatedById, AddressCreatedOn = src.AddressCreatedOn, AddressModifiedById = src.AddressModifiedById, AddressModifiedOn = src.AddressModifiedOn, AddressSortOrder = src.AddressSortOrder, AddressVersion = src.AddressVersion, AddressSourceType = src.AddressSourceType, AddressStatus = src.AddressStatus, }; public Task GetSiteDetails(int partyBranchId, LoginDTO loginDTO) => _partyBranchDAL.GetSiteDetails(partyBranchId, loginDTO); public Task GetSelectListPartyBranch(int firstNumber, int maxResult, CriteriaDTO criteriaDTO, LoginDTO loginDTO) => _partyBranchDAL.GetSelectListPartyBranch(firstNumber, maxResult, criteriaDTO, loginDTO); public Task GetSelectListPartyBranchLinkedParties(int firstNumber, int maxResult, CriteriaDTO criteriaDTO, LoginDTO loginDTO) => _partyBranchDAL.GetSelectListPartyBranch(firstNumber, maxResult, criteriaDTO, loginDTO); // Full-DTO party branch list — same criteria filtering as GetSelectListPartyBranch above, // but no FirstNumber/MaxResult paging, mirroring AccountBLL.GetAccountList's shape. public async Task GetPartyBranchList(CriteriaDTO CriteriaDTO, LoginDTO LoginDTO) { try { return await _partyBranchDAL.GetPartyBranchList(CriteriaDTO, LoginDTO).ConfigureAwait(false); } catch (Exception) { throw; } } public async Task SavePartyBranch(PartyBranchDTO dto, LoginDTO loginDTO) { if (dto == null) throw new ArgumentNullException(nameof(dto)); if (dto.PartyId <= 0 && dto.PartyBranchId > 0) { var existing = await _partyBranchDAL.GetPartyBranch(dto.PartyBranchId, loginDTO).ConfigureAwait(false); if (existing != null) { dto.PartyId = existing.PartyId; } } // if (dto.PartyId <= 0) throw new ArgumentException("Party is required."); if (string.IsNullOrWhiteSpace(dto.PartyBranchName)) throw new ArgumentException("Party branch name is required."); var tx = await _queryExecutor.BeginTransactionAsync(loginDTO).ConfigureAwait(false); try { bool isNew = dto.PartyBranchId == 0; if (isNew) { var auto = await _autoNumber.GetNumberAsync(1, "PARTYBRANCH", loginDTO).ConfigureAwait(false); dto.PartyBranchId = auto.StartNumber; dto.PartyBranchVersion = 1; } else { dto.PartyBranchVersion++; } dto.PartyBranchSourceType = loginDTO.SourceType; dto = await _codeGeneration.AssignCode("PARTYBRANCH", dto, loginDTO).ConfigureAwait(false); if (isNew) await _partyBranchDAL.SavePartyBranch(dto, loginDTO, tx).ConfigureAwait(false); else await _partyBranchDAL.UpdatePartyBranch(dto, loginDTO, tx).ConfigureAwait(false); var addon = dto.PartyBranchAddon?.FirstOrDefault(); if (addon != null && !string.IsNullOrWhiteSpace(addon.FeAddon)) await _partyBranchDAL.SavePartyBranchAddon(dto.PartyBranchId, addon.FeAddon, loginDTO, tx).ConfigureAwait(false); await _queryExecutor.CommitAsync(tx).ConfigureAwait(false); return isNew ? SuccessResponse.SaveSuccess : SuccessResponse.UpdateSuccess; } catch { await _queryExecutor.RollbackAsync(tx).ConfigureAwait(false); throw; } } public async Task DeletePartyBranch(int partyBranchId, LoginDTO loginDTO) { var tx = await _queryExecutor.BeginTransactionAsync(loginDTO).ConfigureAwait(false); try { await _partyBranchDAL.DeletePartyBranch(partyBranchId, loginDTO, tx).ConfigureAwait(false); await _queryExecutor.CommitAsync(tx).ConfigureAwait(false); return "Deleted successfully."; } catch { await _queryExecutor.RollbackAsync(tx).ConfigureAwait(false); throw; } } } }