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.inventory.server.graphql;
018
019import com.echothree.model.control.graphql.server.graphql.BaseEntityInstanceObject;
020import com.echothree.model.control.graphql.server.graphql.UnitCostObject;
021import com.echothree.model.control.graphql.server.graphql.count.Connections;
022import com.echothree.model.control.graphql.server.graphql.count.CountedObjects;
023import com.echothree.model.control.graphql.server.graphql.count.CountingDataConnectionFetcher;
024import com.echothree.model.control.graphql.server.graphql.count.CountingPaginatedData;
025import com.echothree.model.control.graphql.server.util.count.ObjectLimiter;
026import com.echothree.model.control.inventory.server.control.BucketControl;
027import com.echothree.model.control.party.server.control.PartyControl;
028import com.echothree.model.data.inventory.common.InventoryLayerBucketConstants;
029import com.echothree.model.data.inventory.server.entity.InventoryLayer;
030import com.echothree.model.data.inventory.server.entity.InventoryLayerDetail;
031import com.echothree.util.server.persistence.Session;
032import graphql.annotations.annotationTypes.GraphQLDescription;
033import graphql.annotations.annotationTypes.GraphQLField;
034import graphql.annotations.annotationTypes.GraphQLName;
035import graphql.annotations.annotationTypes.GraphQLNonNull;
036import graphql.annotations.connection.GraphQLConnection;
037import graphql.schema.DataFetchingEnvironment;
038import java.util.ArrayList;
039import java.util.stream.Collectors;
040
041@GraphQLDescription("inventory layer object")
042@GraphQLName("InventoryLayer")
043public class InventoryLayerObject
044        extends BaseEntityInstanceObject {
045
046    private final InventoryLayer inventoryLayer; // Always Present
047
048    public InventoryLayerObject(final InventoryLayer inventoryLayer) {
049        super(inventoryLayer.getPrimaryKey());
050
051        this.inventoryLayer = inventoryLayer;
052    }
053
054    private InventoryLayerDetail inventoryLayerDetail; // Optional, use getInventoryLayerDetail()
055
056    private InventoryLayerDetail getInventoryLayerDetail() {
057        if(inventoryLayerDetail == null) {
058            inventoryLayerDetail = inventoryLayer.getLastDetail();
059        }
060
061        return inventoryLayerDetail;
062    }
063
064    @GraphQLField
065    @GraphQLDescription("inventory costing pool")
066    public InventoryCostingPoolObject getInventoryCostingPool(final DataFetchingEnvironment env) {
067        return InventorySecurityUtils.getHasInventoryCostingPoolAccess(env)
068                ? new InventoryCostingPoolObject(getInventoryLayerDetail().getInventoryCostingPool()) : null;
069    }
070
071    @GraphQLField
072    @GraphQLDescription("inventory layer sequence")
073    @GraphQLNonNull
074    public Integer getInventoryLayerSequence() {
075        return getInventoryLayerDetail().getInventoryLayerSequence();
076    }
077
078    // TODO: Add the InventoryTransactionLineObject relationship when transaction-line GraphQL objects are implemented.
079
080    @GraphQLField
081    @GraphQLDescription("receipt quantity")
082    @GraphQLNonNull
083    public Long getReceiptQuantity() {
084        return getInventoryLayerDetail().getReceiptQuantity();
085    }
086
087    @GraphQLField
088    @GraphQLDescription("unit cost")
089    public UnitCostObject getUnitCost() {
090        var unitCost = getInventoryLayerDetail().getUnitCost();
091        var partyControl = Session.getModelController(PartyControl.class);
092
093        return unitCost == null ? null : new UnitCostObject(partyControl.getPreferredCurrency(
094                getInventoryLayerDetail().getInventoryCostingPool().getLastDetail().getCompanyParty()), unitCost);
095    }
096
097    @GraphQLField
098    @GraphQLDescription("description")
099    public String getDescription() {
100        return getInventoryLayerDetail().getDescription();
101    }
102
103    @GraphQLField
104    @GraphQLDescription("inventory layer buckets")
105    @GraphQLNonNull
106    @GraphQLConnection(connectionFetcher = CountingDataConnectionFetcher.class)
107    public CountingPaginatedData<InventoryLayerBucketObject> getInventoryLayerBuckets(final DataFetchingEnvironment env) {
108        if(InventorySecurityUtils.getHasInventoryLayerBucketsAccess(env)) {
109            var bucketControl = Session.getModelController(BucketControl.class);
110            var totalCount = bucketControl.countInventoryLayerBucketsByInventoryLayer(inventoryLayer);
111
112            try(var objectLimiter = new ObjectLimiter(env, InventoryLayerBucketConstants.COMPONENT_VENDOR_NAME,
113                    InventoryLayerBucketConstants.ENTITY_TYPE_NAME, totalCount)) {
114                var entities = bucketControl.getInventoryLayerBucketsByInventoryLayer(inventoryLayer);
115                var inventoryLayerBuckets = entities.stream()
116                        .map(InventoryLayerBucketObject::new)
117                        .collect(Collectors.toCollection(() -> new ArrayList<>(entities.size())));
118
119                return new CountedObjects<>(objectLimiter, inventoryLayerBuckets);
120            }
121        } else {
122            return Connections.emptyConnection();
123        }
124    }
125
126}