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    public PartyTypeObject getPartyType(final DataFetchingEnvironment env) {
096        return PartySecurityUtils.getHasPartyTypeAccess(env) ? new PartyTypeObject(getPartyDetail().getPartyType()) : null;
097    }
098
099    @GraphQLField
100    @GraphQLDescription("preferred language")
101    public LanguageObject getPreferredLanguage(final DataFetchingEnvironment env) {
102        var preferredLanguage = getPartyDetail().getPreferredLanguage();
103        
104        return preferredLanguage != null && PartySecurityUtils.getHasLanguageAccess(env) ? new LanguageObject(preferredLanguage) : null;
105    }
106
107    @GraphQLField
108    @GraphQLDescription("preferred currency")
109    public CurrencyObject getPreferredCurrency(final DataFetchingEnvironment env) {
110        var preferredCurrency = getPartyDetail().getPreferredCurrency();
111        
112        return preferredCurrency != null && AccountingSecurityUtils.getHasCurrencyAccess(env) ? new CurrencyObject(preferredCurrency) : null;
113    }
114
115    @GraphQLField
116    @GraphQLDescription("preferred time zone")
117    public TimeZoneObject getPreferredTimeZone(final DataFetchingEnvironment env) {
118        var preferredTimeZone = getPartyDetail().getPreferredTimeZone();
119        
120        return preferredTimeZone != null && PartySecurityUtils.getHasTimeZoneAccess(env) ? new TimeZoneObject(preferredTimeZone) : null;
121    }
122
123    @GraphQLField
124    @GraphQLDescription("preferred date time format")
125    public DateTimeFormatObject getPreferredDateTimeFormat(final DataFetchingEnvironment env) {
126        var preferredDateTimeFormat = getPartyDetail().getPreferredDateTimeFormat();
127        
128        return preferredDateTimeFormat != null && PartySecurityUtils.getHasDateTimeFormatAccess(env) ? new DateTimeFormatObject(preferredDateTimeFormat) : null;
129    }
130    
131    @GraphQLField
132    @GraphQLDescription("person")
133    public PersonObject getPerson(final DataFetchingEnvironment env) {
134        var partyControl = Session.getModelController(PartyControl.class);
135        var person = partyControl.getPerson(party);
136        
137        return person == null ? null : new PersonObject(person);
138    }
139    
140    @GraphQLField
141    @GraphQLDescription("party group")
142    public PartyGroupObject getPartyGroup(final DataFetchingEnvironment env) {
143        var partyControl = Session.getModelController(PartyControl.class);
144        var partyGroup = partyControl.getPartyGroup(party);
145        
146        return partyGroup == null ? null : new PartyGroupObject(partyGroup);
147    }
148    
149    @GraphQLField
150    @GraphQLDescription("description")
151    @GraphQLNonNull
152    public String getDescription(final DataFetchingEnvironment env) {
153        var partyControl = Session.getModelController(PartyControl.class);
154        var userControl = Session.getModelController(UserControl.class);
155
156        return partyControl.getBestPartyDescription(party, userControl.getPreferredLanguageFromUserVisit(BaseGraphQl.getUserVisit(env)));
157    }
158
159    @GraphQLField
160    @GraphQLDescription("party aliases")
161    @GraphQLNonNull
162    @GraphQLConnection(connectionFetcher = CountingDataConnectionFetcher.class)
163    public CountingPaginatedData<PartyAliasObject> getPartyAliases(final DataFetchingEnvironment env) {
164        if(PartySecurityUtils.getHasPartyAliasesAccess(env, party)) {
165            var partyControl = Session.getModelController(PartyControl.class);
166            var totalCount = partyControl.countPartyAliasesByParty(party);
167
168            try(var objectLimiter = new ObjectLimiter(env, PartyAliasConstants.COMPONENT_VENDOR_NAME, PartyAliasConstants.ENTITY_TYPE_NAME, totalCount)) {
169                var entities = partyControl.getPartyAliasesByParty(party);
170                var partyAliases = entities.stream().map(PartyAliasObject::new).collect(Collectors.toCollection(() -> new ArrayList<>(entities.size())));
171
172                return new CountedObjects<>(objectLimiter, partyAliases);
173            }
174        } else {
175            return Connections.emptyConnection();
176        }
177    }
178
179    @GraphQLField
180    @GraphQLDescription("party contact mechanisms")
181    @GraphQLNonNull
182    @GraphQLConnection(connectionFetcher = CountingDataConnectionFetcher.class)
183    public CountingPaginatedData<PartyContactMechanismObject> getPartyContactMechanisms(final DataFetchingEnvironment env) {
184//        if(ContactSecurityUtils.getHasPartyContactMechanismsAccess(env, party)) {
185            var contactControl = Session.getModelController(ContactControl.class);
186            var totalCount = contactControl.countPartyContactMechanismsByParty(party);
187
188            try(var objectLimiter = new ObjectLimiter(env, PartyContactMechanismConstants.COMPONENT_VENDOR_NAME, PartyContactMechanismConstants.ENTITY_TYPE_NAME, totalCount)) {
189                var entities = contactControl.getPartyContactMechanismsByParty(party);
190                var partyContactMechanismes = entities.stream().map(PartyContactMechanismObject::new).collect(Collectors.toCollection(() -> new ArrayList<>(entities.size())));
191
192                return new CountedObjects<>(objectLimiter, partyContactMechanismes);
193            }
194//        } else {
195//            return Connections.emptyConnection();
196//        }
197    }
198
199    @GraphQLField
200    @GraphQLDescription("party contact mechanism purpose")
201    public PartyContactMechanismPurposeObject getPartyContactMechanismPurpose(final DataFetchingEnvironment env,
202            @GraphQLName("contactMechanismPurposeName") @GraphQLNonNull final String contactMechanismPurposeName) {
203        var commandForm = ContactFormFactory.getGetContactMechanismPurposeForm();
204
205        commandForm.setContactMechanismPurposeName(contactMechanismPurposeName);
206
207        var contactMechanismPurpose = CDI.current().select(GetContactMechanismPurposeCommand.class).get().getEntityForGraphQl(getUserVisitPK(env), commandForm);
208        if(contactMechanismPurpose != null) {
209            var contactControl = Session.getModelController(ContactControl.class);
210            var partyContactMechanismPurpose = contactControl.getDefaultPartyContactMechanismPurpose(party, contactMechanismPurpose);
211
212            return partyContactMechanismPurpose == null ? null : new PartyContactMechanismPurposeObject(partyContactMechanismPurpose);
213        } else {
214            return null;
215        }
216    }
217
218    @GraphQLField
219    @GraphQLDescription("subscriptions")
220    @GraphQLNonNull
221    @GraphQLConnection(connectionFetcher = CountingDataConnectionFetcher.class)
222    public CountingPaginatedData<SubscriptionObject> getSubscriptions(final DataFetchingEnvironment env) {
223        if(SubscriptionSecurityUtils.getHasSubscriptionsAccess(env)) {
224            var subscriptionControl = Session.getModelController(SubscriptionControl.class);
225            var totalCount = subscriptionControl.countSubscriptionsByParty(party);
226
227            try(var objectLimiter = new ObjectLimiter(env, SubscriptionConstants.COMPONENT_VENDOR_NAME, SubscriptionConstants.ENTITY_TYPE_NAME, totalCount)) {
228                var entities = subscriptionControl.getSubscriptionsByParty(party);
229                var subscriptions = entities.stream().map(SubscriptionObject::new).collect(Collectors.toCollection(() -> new ArrayList<>(entities.size())));
230
231                return new CountedObjects<>(objectLimiter, subscriptions);
232            }
233        } else {
234            return Connections.emptyConnection();
235        }
236    }
237
238    @GraphQLField
239    @GraphQLDescription("party contact lists")
240    @GraphQLNonNull
241    @GraphQLConnection(connectionFetcher = CountingDataConnectionFetcher.class)
242    public CountingPaginatedData<PartyContactListObject> getPartyContactLists(final DataFetchingEnvironment env) {
243        if(ContactListSecurityUtils.getHasPartyContactListsAccess(env)) {
244            var contactListControl = Session.getModelController(ContactListControl.class);
245            var totalCount = contactListControl.countPartyContactListsByParty(party);
246
247            try(var objectLimiter = new ObjectLimiter(env, PartyContactListConstants.COMPONENT_VENDOR_NAME, PartyContactListConstants.ENTITY_TYPE_NAME, totalCount)) {
248                var entities = contactListControl.getPartyContactListsByParty(party);
249                var partyContactLists = entities.stream().map(PartyContactListObject::new).collect(Collectors.toCollection(() -> new ArrayList<>(entities.size())));
250
251                return new CountedObjects<>(objectLimiter, partyContactLists);
252            }
253        } else {
254            return Connections.emptyConnection();
255        }
256    }
257
258    @GraphQLField
259    @GraphQLDescription("party inventory costing method")
260    public PartyInventoryCostingMethodObject getPartyInventoryCostingMethod(final DataFetchingEnvironment env) {
261        if(InventorySecurityUtils.getHasPartyInventoryCostingMethodAccess(env)) {
262            var inventoryCostingMethodControl = Session.getModelController(InventoryCostingMethodControl.class);
263            var partyInventoryCostingMethod = inventoryCostingMethodControl.getPartyInventoryCostingMethod(party);
264
265            return partyInventoryCostingMethod == null ? null : new PartyInventoryCostingMethodObject(partyInventoryCostingMethod);
266        } else {
267            return null;
268        }
269    }
270
271    @GraphQLField
272    @GraphQLDescription("party bucket")
273    @GraphQLNonNull
274    @GraphQLConnection(connectionFetcher = CountingDataConnectionFetcher.class)
275    public CountingPaginatedData<PartyBucketObject> getPartyBuckets(final DataFetchingEnvironment env) {
276        if(InventorySecurityUtils.getHasPartyBucketsAccess(env)) {
277            var contactListControl = Session.getModelController(BucketControl.class);
278            var totalCount = contactListControl.countPartyBucketsByParty(party);
279
280            try(var objectLimiter = new ObjectLimiter(env, PartyBucketConstants.COMPONENT_VENDOR_NAME, PartyBucketConstants.ENTITY_TYPE_NAME, totalCount)) {
281                var entities = contactListControl.getPartyBucketsByParty(party);
282                var partyBuckets = entities.stream().map(PartyBucketObject::new).collect(Collectors.toCollection(() -> new ArrayList<>(entities.size())));
283
284                return new CountedObjects<>(objectLimiter, partyBuckets);
285            }
286        } else {
287            return Connections.emptyConnection();
288        }
289    }
290
291}