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.period.server.graphql;
018
019import com.echothree.control.user.period.common.PeriodUtil;
020import com.echothree.control.user.period.server.command.GetFiscalPeriodsCommand;
021import com.echothree.model.control.graphql.server.graphql.BaseEntityInstanceObject;
022import com.echothree.model.control.graphql.server.graphql.TimeObject;
023import com.echothree.model.control.graphql.server.graphql.count.Connections;
024import com.echothree.model.control.graphql.server.graphql.count.CountedObjects;
025import com.echothree.model.control.graphql.server.graphql.count.CountingDataConnectionFetcher;
026import com.echothree.model.control.graphql.server.graphql.count.CountingPaginatedData;
027import com.echothree.model.control.graphql.server.util.BaseGraphQl;
028import com.echothree.model.control.graphql.server.util.count.ObjectLimiter;
029import com.echothree.model.control.period.server.control.PeriodControl;
030import com.echothree.model.control.user.server.control.UserControl;
031import com.echothree.model.data.period.common.PeriodConstants;
032import com.echothree.model.data.period.server.entity.Period;
033import com.echothree.model.data.period.server.entity.PeriodDetail;
034import com.echothree.util.server.persistence.Session;
035import graphql.annotations.annotationTypes.GraphQLDescription;
036import graphql.annotations.annotationTypes.GraphQLField;
037import graphql.annotations.annotationTypes.GraphQLName;
038import graphql.annotations.annotationTypes.GraphQLNonNull;
039import graphql.annotations.connection.GraphQLConnection;
040import graphql.schema.DataFetchingEnvironment;
041import java.util.ArrayList;
042import javax.enterprise.inject.spi.CDI;
043import javax.naming.NamingException;
044import static com.echothree.model.control.period.common.PeriodConstants.PeriodKind_FISCAL;
045
046public abstract class PeriodObject
047        extends BaseEntityInstanceObject {
048
049    protected final Period period; // Always Present
050
051    protected PeriodObject(Period period) {
052        super(period.getPrimaryKey());
053
054        this.period = period;
055    }
056
057    private PeriodDetail periodDetail; // Optional, use getPeriodDetail()
058
059    protected PeriodDetail getPeriodDetail() {
060        if(periodDetail == null) {
061            periodDetail = period.getLastDetail();
062        }
063
064        return periodDetail;
065    }
066
067    public static PeriodInterface toPeriodInterface(Period period) {
068        return period == null ?
069                null :
070                switch(period.getLastDetail().getPeriodKind().getLastDetail().getPeriodKindName()) {
071                    case PeriodKind_FISCAL -> new FiscalPeriodObject(period);
072                    default -> null;
073                };
074    }
075
076    @GraphQLField
077    @GraphQLNonNull
078    public String getPeriodName() {
079        return getPeriodDetail().getPeriodName();
080    }
081
082    @GraphQLField
083    public PeriodKindObject getPeriodKind(final DataFetchingEnvironment env) {
084        return PeriodSecurityUtils.getHasPeriodKindAccess(env) ? new PeriodKindObject(getPeriodDetail().getPeriodKind()) : null;
085    }
086
087    @GraphQLField
088    public PeriodTypeObject getPeriodType(final DataFetchingEnvironment env) {
089        if(PeriodSecurityUtils.getHasPeriodTypeAccess(env)) {
090            var periodType = getPeriodDetail().getPeriodType();
091
092            return periodType == null ? null : new PeriodTypeObject(periodType);
093        } else {
094            return null;
095        }
096    }
097
098    @GraphQLField
099    public PeriodInterface getParentPeriod(final DataFetchingEnvironment env) {
100        return PeriodSecurityUtils.getHasFiscalPeriodAccess(env) ? toPeriodInterface(getPeriodDetail().getParentPeriod()) : null;
101    }
102
103    @GraphQLField
104    @GraphQLNonNull
105    public TimeObject getStartTime() {
106        return new TimeObject(getPeriodDetail().getStartTime());
107    }
108
109    @GraphQLField
110    @GraphQLNonNull
111    public TimeObject getEndTime() {
112        return new TimeObject(getPeriodDetail().getEndTime());
113    }
114
115    @GraphQLField
116    @GraphQLNonNull
117    public String getDescription(final DataFetchingEnvironment env) {
118        var periodControl = Session.getModelController(PeriodControl.class);
119        var userControl = Session.getModelController(UserControl.class);
120
121        return periodControl.getBestPeriodDescription(period, userControl.getPreferredLanguageFromUserVisit(BaseGraphQl.getUserVisit(env)));
122    }
123
124    @GraphQLField
125    @GraphQLDescription("child periods")
126    @GraphQLNonNull
127    @GraphQLConnection(connectionFetcher = CountingDataConnectionFetcher.class)
128    public CountingPaginatedData<PeriodInterface> getPeriods(final DataFetchingEnvironment env) {
129        return getPeriods(env, getPeriodDetail().getPeriodKind().getLastDetail().getPeriodKindName(),
130                getPeriodName(), null);
131    }
132
133    public static CountingPaginatedData<PeriodInterface> getPeriods(final DataFetchingEnvironment env,
134            final String periodKindName, final String parentPeriodName, final String periodTypeName) {
135        if(PeriodKind_FISCAL.equals(periodKindName) && PeriodSecurityUtils.getHasFiscalPeriodsAccess(env)) {
136            try {
137                var form = PeriodUtil.getHome().getGetFiscalPeriodsForm();
138                var command = CDI.current().select(GetFiscalPeriodsCommand.class).get();
139
140                form.setParentPeriodName(parentPeriodName);
141                form.setPeriodTypeName(periodTypeName);
142
143                var total = command.getTotalEntitiesForGraphQl(BaseGraphQl.getUserVisitPK(env), form);
144                if(total == null) {
145                    return Connections.emptyConnection();
146                }
147
148                try(var objectLimiter = new ObjectLimiter(env, PeriodConstants.COMPONENT_VENDOR_NAME,
149                        PeriodConstants.ENTITY_TYPE_NAME, total)) {
150                    var entities = command.getEntitiesForGraphQl(BaseGraphQl.getUserVisitPK(env), form);
151                    var objects = new ArrayList<PeriodInterface>(entities.size());
152
153                    for(var entity : entities) {
154                        objects.add(toPeriodInterface(entity));
155                    }
156
157                    return new CountedObjects<>(objectLimiter, objects);
158                }
159            } catch(NamingException ex) {
160                throw new RuntimeException(ex);
161            }
162        } else {
163            return Connections.emptyConnection();
164        }
165    }
166
167}