001// --------------------------------------------------------------------------------
002// Copyright 2002-2026 Echo Three, LLC
003//
004// Licensed under the Apache License, Version 2.0 (the "License");
005// you may not use this file except in compliance with the License.
006// You may obtain a copy of the License at
007//
008//     http://www.apache.org/licenses/LICENSE-2.0
009//
010// Unless required by applicable law or agreed to in writing, software
011// distributed under the License is distributed on an "AS IS" BASIS,
012// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013// See the License for the specific language governing permissions and
014// limitations under the License.
015// --------------------------------------------------------------------------------
016
017package com.echothree.model.control.party.server.graphql;
018
019import com.echothree.control.user.contact.common.form.ContactFormFactory;
020import com.echothree.control.user.contact.server.command.GetContactMechanismPurposeCommand;
021import com.echothree.model.control.accounting.server.graphql.AccountingSecurityUtils;
022import com.echothree.model.control.accounting.server.graphql.CurrencyObject;
023import com.echothree.model.control.contact.server.control.ContactControl;
024import com.echothree.model.control.contact.server.graphql.PartyContactMechanismObject;
025import com.echothree.model.control.contact.server.graphql.PartyContactMechanismPurposeObject;
026import com.echothree.model.control.contactlist.server.control.ContactListControl;
027import com.echothree.model.control.contactlist.server.graphql.ContactListSecurityUtils;
028import com.echothree.model.control.contactlist.server.graphql.PartyContactListObject;
029import com.echothree.model.control.graphql.server.graphql.BaseEntityInstanceObject;
030import com.echothree.model.control.graphql.server.graphql.count.Connections;
031import com.echothree.model.control.graphql.server.graphql.count.CountedObjects;
032import com.echothree.model.control.graphql.server.graphql.count.CountingDataConnectionFetcher;
033import com.echothree.model.control.graphql.server.graphql.count.CountingPaginatedData;
034import com.echothree.model.control.graphql.server.util.BaseGraphQl;
035import static com.echothree.model.control.graphql.server.util.BaseGraphQl.getUserVisitPK;
036import com.echothree.model.control.graphql.server.util.count.ObjectLimiter;
037import com.echothree.model.control.inventory.server.control.BucketControl;
038import com.echothree.model.control.inventory.server.control.InventoryCostingMethodControl;
039import com.echothree.model.control.inventory.server.graphql.InventorySecurityUtils;
040import com.echothree.model.control.inventory.server.graphql.PartyBucketObject;
041import com.echothree.model.control.inventory.server.graphql.PartyInventoryCostingMethodObject;
042import com.echothree.model.control.party.server.control.PartyControl;
043import com.echothree.model.control.subscription.server.control.SubscriptionControl;
044import com.echothree.model.control.subscription.server.graphql.SubscriptionObject;
045import com.echothree.model.control.subscription.server.graphql.SubscriptionSecurityUtils;
046import com.echothree.model.control.user.server.control.UserControl;
047import com.echothree.model.data.contact.common.PartyContactMechanismConstants;
048import com.echothree.model.data.contactlist.common.PartyContactListConstants;
049import com.echothree.model.data.inventory.common.PartyBucketConstants;
050import com.echothree.model.data.party.common.PartyAliasConstants;
051import com.echothree.model.data.party.server.entity.Party;
052import com.echothree.model.data.party.server.entity.PartyDetail;
053import com.echothree.model.data.subscription.common.SubscriptionConstants;
054import com.echothree.util.server.persistence.Session;
055import graphql.annotations.annotationTypes.GraphQLDescription;
056import graphql.annotations.annotationTypes.GraphQLField;
057import graphql.annotations.annotationTypes.GraphQLName;
058import graphql.annotations.annotationTypes.GraphQLNonNull;
059import graphql.annotations.connection.GraphQLConnection;
060import graphql.schema.DataFetchingEnvironment;
061import java.util.ArrayList;
062import java.util.stream.Collectors;
063import javax.enterprise.inject.spi.CDI;
064
065public abstract class BasePartyObject
066        extends BaseEntityInstanceObject {
067
068    protected final Party party; // Always Present
069
070    protected BasePartyObject(Party party) {
071        super(party.getPrimaryKey());
072        
073        this.party = party;
074    }
075
076    private PartyDetail partyDetail; // Optional, use getPartyDetail()
077
078    protected PartyDetail getPartyDetail() {
079        if(partyDetail == null) {
080            partyDetail = party.getLastDetail();
081        }
082        
083        return partyDetail;
084    }
085    
086    @GraphQLField
087    @GraphQLDescription("party name")
088    @GraphQLNonNull
089    public String getPartyName() {
090        return getPartyDetail().getPartyName();
091    }
092
093    @GraphQLField
094    @GraphQLDescription("party type")
095    @GraphQLNonNull
096    public PartyTypeObject getPartyType(final DataFetchingEnvironment env) {
097        return PartySecurityUtils.getHasPartyTypeAccess(env) ? new PartyTypeObject(getPartyDetail().getPartyType()) : null;
098    }
099
100    @GraphQLField
101    @GraphQLDescription("preferred language")
102    public LanguageObject getPreferredLanguage(final DataFetchingEnvironment env) {
103        var preferredLanguage = getPartyDetail().getPreferredLanguage();
104        
105        return preferredLanguage != null && PartySecurityUtils.getHasLanguageAccess(env) ? new LanguageObject(preferredLanguage) : null;
106    }
107
108    @GraphQLField
109    @GraphQLDescription("preferred currency")
110    public CurrencyObject getPreferredCurrency(final DataFetchingEnvironment env) {
111        var preferredCurrency = getPartyDetail().getPreferredCurrency();
112        
113        return preferredCurrency != null && AccountingSecurityUtils.getHasCurrencyAccess(env) ? new CurrencyObject(preferredCurrency) : null;
114    }
115
116    @GraphQLField
117    @GraphQLDescription("preferred time zone")
118    public TimeZoneObject getPreferredTimeZone(final DataFetchingEnvironment env) {
119        var preferredTimeZone = getPartyDetail().getPreferredTimeZone();
120        
121        return preferredTimeZone != null && PartySecurityUtils.getHasTimeZoneAccess(env) ? new TimeZoneObject(preferredTimeZone) : null;
122    }
123
124    @GraphQLField
125    @GraphQLDescription("preferred date time format")
126    public DateTimeFormatObject getPreferredDateTimeFormat(final DataFetchingEnvironment env) {
127        var preferredDateTimeFormat = getPartyDetail().getPreferredDateTimeFormat();
128        
129        return preferredDateTimeFormat != null && PartySecurityUtils.getHasDateTimeFormatAccess(env) ? new DateTimeFormatObject(preferredDateTimeFormat) : null;
130    }
131    
132    @GraphQLField
133    @GraphQLDescription("person")
134    public PersonObject getPerson(final DataFetchingEnvironment env) {
135        var partyControl = Session.getModelController(PartyControl.class);
136        var person = partyControl.getPerson(party);
137        
138        return person == null ? null : new PersonObject(person);
139    }
140    
141    @GraphQLField
142    @GraphQLDescription("party group")
143    public PartyGroupObject getPartyGroup(final DataFetchingEnvironment env) {
144        var partyControl = Session.getModelController(PartyControl.class);
145        var partyGroup = partyControl.getPartyGroup(party);
146        
147        return partyGroup == null ? null : new PartyGroupObject(partyGroup);
148    }
149    
150    @GraphQLField
151    @GraphQLDescription("description")
152    @GraphQLNonNull
153    public String getDescription(final DataFetchingEnvironment env) {
154        var partyControl = Session.getModelController(PartyControl.class);
155        var userControl = Session.getModelController(UserControl.class);
156
157        return partyControl.getBestPartyDescription(party, userControl.getPreferredLanguageFromUserVisit(BaseGraphQl.getUserVisit(env)));
158    }
159
160    @GraphQLField
161    @GraphQLDescription("party aliases")
162    @GraphQLNonNull
163    @GraphQLConnection(connectionFetcher = CountingDataConnectionFetcher.class)
164    public CountingPaginatedData<PartyAliasObject> getPartyAliases(final DataFetchingEnvironment env) {
165        if(PartySecurityUtils.getHasPartyAliasesAccess(env, party)) {
166            var partyControl = Session.getModelController(PartyControl.class);
167            var totalCount = partyControl.countPartyAliasesByParty(party);
168
169            try(var objectLimiter = new ObjectLimiter(env, PartyAliasConstants.COMPONENT_VENDOR_NAME, PartyAliasConstants.ENTITY_TYPE_NAME, totalCount)) {
170                var entities = partyControl.getPartyAliasesByParty(party);
171                var partyAliases = entities.stream().map(PartyAliasObject::new).collect(Collectors.toCollection(() -> new ArrayList<>(entities.size())));
172
173                return new CountedObjects<>(objectLimiter, partyAliases);
174            }
175        } else {
176            return Connections.emptyConnection();
177        }
178    }
179
180    @GraphQLField
181    @GraphQLDescription("party contact mechanisms")
182    @GraphQLNonNull
183    @GraphQLConnection(connectionFetcher = CountingDataConnectionFetcher.class)
184    public CountingPaginatedData<PartyContactMechanismObject> getPartyContactMechanisms(final DataFetchingEnvironment env) {
185//        if(ContactSecurityUtils.getHasPartyContactMechanismsAccess(env, party)) {
186            var contactControl = Session.getModelController(ContactControl.class);
187            var totalCount = contactControl.countPartyContactMechanismsByParty(party);
188
189            try(var objectLimiter = new ObjectLimiter(env, PartyContactMechanismConstants.COMPONENT_VENDOR_NAME, PartyContactMechanismConstants.ENTITY_TYPE_NAME, totalCount)) {
190                var entities = contactControl.getPartyContactMechanismsByParty(party);
191                var partyContactMechanismes = entities.stream().map(PartyContactMechanismObject::new).collect(Collectors.toCollection(() -> new ArrayList<>(entities.size())));
192
193                return new CountedObjects<>(objectLimiter, partyContactMechanismes);
194            }
195//        } else {
196//            return Connections.emptyConnection();
197//        }
198    }
199
200    @GraphQLField
201    @GraphQLDescription("party contact mechanism purpose")
202    public PartyContactMechanismPurposeObject getPartyContactMechanismPurpose(final DataFetchingEnvironment env,
203            @GraphQLName("contactMechanismPurposeName") @GraphQLNonNull final String contactMechanismPurposeName) {
204        var commandForm = ContactFormFactory.getGetContactMechanismPurposeForm();
205
206        commandForm.setContactMechanismPurposeName(contactMechanismPurposeName);
207
208        var contactMechanismPurpose = CDI.current().select(GetContactMechanismPurposeCommand.class).get().getEntityForGraphQl(getUserVisitPK(env), commandForm);
209        if(contactMechanismPurpose != null) {
210            var contactControl = Session.getModelController(ContactControl.class);
211            var partyContactMechanismPurpose = contactControl.getDefaultPartyContactMechanismPurpose(party, contactMechanismPurpose);
212
213            return partyContactMechanismPurpose == null ? null : new PartyContactMechanismPurposeObject(partyContactMechanismPurpose);
214        } else {
215            return null;
216        }
217    }
218
219    @GraphQLField
220    @GraphQLDescription("subscriptions")
221    @GraphQLNonNull
222    @GraphQLConnection(connectionFetcher = CountingDataConnectionFetcher.class)
223    public CountingPaginatedData<SubscriptionObject> getSubscriptions(final DataFetchingEnvironment env) {
224        if(SubscriptionSecurityUtils.getHasSubscriptionsAccess(env)) {
225            var subscriptionControl = Session.getModelController(SubscriptionControl.class);
226            var totalCount = subscriptionControl.countSubscriptionsByParty(party);
227
228            try(var objectLimiter = new ObjectLimiter(env, SubscriptionConstants.COMPONENT_VENDOR_NAME, SubscriptionConstants.ENTITY_TYPE_NAME, totalCount)) {
229                var entities = subscriptionControl.getSubscriptionsByParty(party);
230                var subscriptions = entities.stream().map(SubscriptionObject::new).collect(Collectors.toCollection(() -> new ArrayList<>(entities.size())));
231
232                return new CountedObjects<>(objectLimiter, subscriptions);
233            }
234        } else {
235            return Connections.emptyConnection();
236        }
237    }
238
239    @GraphQLField
240    @GraphQLDescription("party contact lists")
241    @GraphQLNonNull
242    @GraphQLConnection(connectionFetcher = CountingDataConnectionFetcher.class)
243    public CountingPaginatedData<PartyContactListObject> getPartyContactLists(final DataFetchingEnvironment env) {
244        if(ContactListSecurityUtils.getHasPartyContactListsAccess(env)) {
245            var contactListControl = Session.getModelController(ContactListControl.class);
246            var totalCount = contactListControl.countPartyContactListsByParty(party);
247
248            try(var objectLimiter = new ObjectLimiter(env, PartyContactListConstants.COMPONENT_VENDOR_NAME, PartyContactListConstants.ENTITY_TYPE_NAME, totalCount)) {
249                var entities = contactListControl.getPartyContactListsByParty(party);
250                var partyContactLists = entities.stream().map(PartyContactListObject::new).collect(Collectors.toCollection(() -> new ArrayList<>(entities.size())));
251
252                return new CountedObjects<>(objectLimiter, partyContactLists);
253            }
254        } else {
255            return Connections.emptyConnection();
256        }
257    }
258
259    @GraphQLField
260    @GraphQLDescription("party inventory costing method")
261    public PartyInventoryCostingMethodObject getPartyInventoryCostingMethod(final DataFetchingEnvironment env) {
262        if(InventorySecurityUtils.getHasPartyInventoryCostingMethodAccess(env)) {
263            var inventoryCostingMethodControl = Session.getModelController(InventoryCostingMethodControl.class);
264            var partyInventoryCostingMethod = inventoryCostingMethodControl.getPartyInventoryCostingMethod(party);
265
266            return partyInventoryCostingMethod == null ? null : new PartyInventoryCostingMethodObject(partyInventoryCostingMethod);
267        } else {
268            return null;
269        }
270    }
271
272    @GraphQLField
273    @GraphQLDescription("party bucket")
274    @GraphQLNonNull
275    @GraphQLConnection(connectionFetcher = CountingDataConnectionFetcher.class)
276    public CountingPaginatedData<PartyBucketObject> getPartyBuckets(final DataFetchingEnvironment env) {
277        if(InventorySecurityUtils.getHasPartyBucketsAccess(env)) {
278            var contactListControl = Session.getModelController(BucketControl.class);
279            var totalCount = contactListControl.countPartyBucketsByParty(party);
280
281            try(var objectLimiter = new ObjectLimiter(env, PartyBucketConstants.COMPONENT_VENDOR_NAME, PartyBucketConstants.ENTITY_TYPE_NAME, totalCount)) {
282                var entities = contactListControl.getPartyBucketsByParty(party);
283                var partyBuckets = entities.stream().map(PartyBucketObject::new).collect(Collectors.toCollection(() -> new ArrayList<>(entities.size())));
284
285                return new CountedObjects<>(objectLimiter, partyBuckets);
286            }
287        } else {
288            return Connections.emptyConnection();
289        }
290    }
291
292}