11/* eslint-disable no-continue */
22import { Error404 } from '@crowd/common'
3+ import {
4+ OrganizationField ,
5+ cleanSoftDeletedMemberOrganization ,
6+ createMemberOrganization ,
7+ deleteMemberOrganization ,
8+ fetchMemberOrganizations ,
9+ queryOrgs ,
10+ updateMemberOrganization ,
11+ } from '@crowd/data-access-layer'
12+ import { findOverrides as findMemberOrganizationAffiliationOverrides } from '@crowd/data-access-layer/src/member_organization_affiliation_overrides'
313import { LoggerBase } from '@crowd/logging'
4- import { IMemberOrganization , IOrganization } from '@crowd/types'
14+ import { IMemberOrganization , IOrganization , IRenderFriendlyMemberOrganization } from '@crowd/types'
515
6- import MemberOrganizationsRepository from '@/database/repositories/member/memberOrganizationsRepository '
16+ import SequelizeRepository from '@/database/repositories/sequelizeRepository '
717
818import { IServiceOptions } from '../IServiceOptions'
919import MemberAffiliationService from '../memberAffiliationService'
1020
21+ type IOrganizationSummary = Pick < IOrganization , 'id' | 'displayName' | 'logo' >
22+
1123export default class MemberOrganizationsService extends LoggerBase {
1224 options : IServiceOptions
1325
@@ -17,70 +29,155 @@ export default class MemberOrganizationsService extends LoggerBase {
1729 }
1830
1931 // Member organization list
20- async list ( memberId : string ) : Promise < IOrganization [ ] > {
21- return MemberOrganizationsRepository . list ( memberId , this . options )
22- }
32+ async list ( memberId : string ) : Promise < IRenderFriendlyMemberOrganization [ ] > {
33+ const qx = SequelizeRepository . getQueryExecutor ( this . options )
2334
24- // Member organization creation
25- async create ( memberId : string , data : Partial < IMemberOrganization > ) : Promise < IOrganization [ ] > {
26- const memberOrganizations = await MemberOrganizationsRepository . create (
35+ // Fetch member organizations
36+ const memberOrganizations : IMemberOrganization [ ] = await fetchMemberOrganizations ( qx , memberId )
37+
38+ if ( memberOrganizations . length === 0 ) {
39+ return [ ]
40+ }
41+
42+ // Parse unique organization ids
43+ const orgIds : string [ ] = [ ...new Set ( memberOrganizations . map ( ( mo ) => mo . organizationId ) ) ]
44+
45+ // Fetch organizations
46+ let organizations : IOrganizationSummary [ ] = [ ]
47+ if ( orgIds . length ) {
48+ organizations = await queryOrgs ( qx , {
49+ filter : {
50+ [ OrganizationField . ID ] : {
51+ in : orgIds ,
52+ } ,
53+ } ,
54+ fields : [ OrganizationField . ID , OrganizationField . DISPLAY_NAME , OrganizationField . LOGO ] ,
55+ } )
56+ }
57+
58+ // Fetch affiliation overrides
59+ const affiliationOverrides = await findMemberOrganizationAffiliationOverrides (
60+ qx ,
2761 memberId ,
28- data ,
29- this . options ,
62+ memberOrganizations . map ( ( mo ) => mo . id ) ,
3063 )
31- await MemberAffiliationService . startAffiliationRecalculation (
32- memberId ,
33- [ data . organizationId ] ,
34- this . options ,
64+
65+ // Create mapping by id to speed up the processing
66+ const orgByid : Record < string , IOrganizationSummary > = organizations . reduce (
67+ ( obj : Record < string , IOrganizationSummary > , org ) => ( {
68+ ...obj ,
69+ [ org . id ] : org ,
70+ } ) ,
71+ { } ,
3572 )
36- return memberOrganizations
73+
74+ // Format the results
75+ return memberOrganizations . map ( ( mo ) => ( {
76+ ...( orgByid [ mo . organizationId ] || { } ) ,
77+ id : mo . organizationId ,
78+ memberOrganizations : {
79+ ...mo ,
80+ affiliationOverride : affiliationOverrides . find ( ( ao ) => ao . memberOrganizationId === mo . id ) ,
81+ } ,
82+ } ) )
83+ }
84+
85+ // Member organization creation
86+ async create (
87+ memberId : string ,
88+ data : Partial < IMemberOrganization > ,
89+ ) : Promise < IRenderFriendlyMemberOrganization [ ] > {
90+ const transaction = await SequelizeRepository . createTransaction ( this . options )
91+ const repositoryOptions = { ...this . options , transaction }
92+
93+ try {
94+ const qx = SequelizeRepository . getQueryExecutor ( repositoryOptions )
95+
96+ // Clean up any soft-deleted entries
97+ await cleanSoftDeletedMemberOrganization ( qx , memberId , data . organizationId , data )
98+
99+ // Create new member organization
100+ await createMemberOrganization ( qx , memberId , data )
101+
102+ // Start affiliation recalculation within the same transaction
103+ await MemberAffiliationService . startAffiliationRecalculation (
104+ memberId ,
105+ [ data . organizationId ] ,
106+ repositoryOptions ,
107+ )
108+
109+ // Fetch updated list
110+ const result = await this . list ( memberId )
111+
112+ await SequelizeRepository . commitTransaction ( transaction )
113+ return result
114+ } catch ( error ) {
115+ await SequelizeRepository . rollbackTransaction ( transaction )
116+ throw error
117+ }
37118 }
38119
39120 // Update member organization
40121 async update (
41122 id : string ,
42123 memberId : string ,
43124 data : Partial < IMemberOrganization > ,
44- ) : Promise < IOrganization [ ] > {
45- const memberOrganizations = await MemberOrganizationsRepository . update (
46- id ,
47- memberId ,
48- data ,
49- this . options ,
50- )
51- await MemberAffiliationService . startAffiliationRecalculation (
52- memberId ,
53- [ data . organizationId ] ,
54- this . options ,
55- )
56- return memberOrganizations
125+ ) : Promise < IRenderFriendlyMemberOrganization [ ] > {
126+ const transaction = await SequelizeRepository . createTransaction ( this . options )
127+ const repositoryOptions = { ...this . options , transaction }
128+
129+ try {
130+ const qx = SequelizeRepository . getQueryExecutor ( repositoryOptions )
131+
132+ await cleanSoftDeletedMemberOrganization ( qx , memberId , data . organizationId , data )
133+ await updateMemberOrganization ( qx , memberId , id , data )
134+
135+ await MemberAffiliationService . startAffiliationRecalculation (
136+ memberId ,
137+ [ data . organizationId ] ,
138+ repositoryOptions ,
139+ )
140+
141+ const result = await this . list ( memberId )
142+
143+ await SequelizeRepository . commitTransaction ( transaction )
144+ return result
145+ } catch ( error ) {
146+ await SequelizeRepository . rollbackTransaction ( transaction )
147+ throw error
148+ }
57149 }
58150
59151 // Delete member organization
60- async delete ( id : string , memberId : string ) : Promise < IOrganization [ ] > {
61- const existingMemberOrganizations = await MemberOrganizationsRepository . list (
62- memberId ,
63- this . options ,
64- )
65- const memberOrganizationToBeDeleted = existingMemberOrganizations . find (
66- ( mo ) => mo . memberOrganizations . id === id ,
67- )
68- if ( ! memberOrganizationToBeDeleted ) {
69- throw new Error404 ( `Member organization with id ${ id } not found!` )
70- }
152+ async delete ( id : string , memberId : string ) : Promise < IRenderFriendlyMemberOrganization [ ] > {
153+ const transaction = await SequelizeRepository . createTransaction ( this . options )
154+ const repositoryOptions = { ...this . options , transaction }
71155
72- const remainingMemberOrganizations = await MemberOrganizationsRepository . delete (
73- id ,
74- memberId ,
75- this . options ,
76- )
156+ try {
157+ const qx = SequelizeRepository . getQueryExecutor ( repositoryOptions )
77158
78- await MemberAffiliationService . startAffiliationRecalculation (
79- memberId ,
80- [ memberOrganizationToBeDeleted . memberOrganizations . organizationId ] ,
81- this . options ,
82- )
159+ const existingMemberOrganizations = await fetchMemberOrganizations ( qx , memberId )
160+ const memberOrganizationToBeDeleted = existingMemberOrganizations . find ( ( mo ) => mo . id === id )
83161
84- return remainingMemberOrganizations
162+ if ( ! memberOrganizationToBeDeleted ) {
163+ throw new Error404 ( `Member organization with id ${ id } not found!` )
164+ }
165+
166+ await deleteMemberOrganization ( qx , memberId , id )
167+
168+ await MemberAffiliationService . startAffiliationRecalculation (
169+ memberId ,
170+ [ memberOrganizationToBeDeleted . organizationId ] ,
171+ repositoryOptions ,
172+ )
173+
174+ const result = await this . list ( memberId )
175+
176+ await SequelizeRepository . commitTransaction ( transaction )
177+ return result
178+ } catch ( error ) {
179+ await SequelizeRepository . rollbackTransaction ( transaction )
180+ throw error
181+ }
85182 }
86183}
0 commit comments