/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
*/
package org.apache.ofbiz.product.facility.shipment

// This script gets shipment items grouped by package for use in the packing slip PDF or any screens that require by-package layout

import org.apache.ofbiz.base.util.ObjectType
import org.apache.ofbiz.base.util.UtilMisc
import org.apache.ofbiz.entity.condition.EntityCondition
import org.apache.ofbiz.entity.condition.EntityOperator
import org.apache.ofbiz.entity.util.EntityTypeUtil

// Since this script is run after ViewShipment, we will re-use the shipment in the context
shipment = context.shipment
if (!shipment) {
    return
}

// get the packages related to this shipment in order of packages
shipmentPackages = shipment.getRelated('ShipmentPackage', null, ['shipmentPackageSeqId'], false)

// first we scan the shipment items and count the quantity of each product that is being shipped
quantityShippedByProduct = [:]
quantityInShipmentByProduct = [:]
shipmentItems = shipment.getRelated('ShipmentItem', null, null, false)
shipmentItems.each { shipmentItem ->
    productId = shipmentItem.productId
    shipped = quantityShippedByProduct.get(productId) ?: 0 as Double
    shipped += shipmentItem.getDouble('quantity').doubleValue()
    quantityShippedByProduct.put(productId, shipped)
    quantityInShipmentByProduct.put(productId, shipped)
}

// Add in the total of all previously shipped items
previousShipmentIter = from('Shipment')
                            .where(EntityCondition.makeCondition(
                                    UtilMisc.toList(
                                                EntityCondition.makeCondition('primaryOrderId', shipment.getString('primaryOrderId')),
                                                EntityCondition.makeCondition('shipmentTypeId', 'SALES_SHIPMENT'),
                                                EntityCondition.makeCondition('createdDate', EntityOperator.LESS_THAN_EQUAL_TO,
                                                    ObjectType.simpleTypeOrObjectConvert(shipment.getString('createdDate'), 'Timestamp', null, null))
                                            ),
                                        EntityOperator.AND))
                            .queryIterator()

while (previousShipmentIter.hasNext()) {
    previousShipmentItem = previousShipmentIter.next()
    if (previousShipmentItem.shipmentId != shipment.shipmentId) {
        previousShipmentItems = previousShipmentItem.getRelated('ShipmentItem', null, null, false)
        previousShipmentItems.each { shipmentItem ->
            productId = shipmentItem.productId
            shipped = quantityShippedByProduct.get(productId) ?: 0 as Double
            shipped += shipmentItem.getDouble('quantity').doubleValue()
            quantityShippedByProduct.put(productId, shipped)
        }
    }
}
previousShipmentIter.close()

// next scan the order items (via issuances) to count the quantity of each product requested
quantityRequestedByProduct = [:]
countedOrderItems = [:] // this map is only used to keep track of the order items already counted
order = shipment.getRelatedOne('PrimaryOrderHeader', false)
issuances = order.getRelated('ItemIssuance', null, null, false)
issuances.each { issuance ->
    orderItem = issuance.getRelatedOne('OrderItem', false)
    productId = orderItem.productId
    if (!countedOrderItems.containsKey(orderItem.orderId + orderItem.orderItemSeqId)) {
        countedOrderItems.put(orderItem.orderId + orderItem.orderItemSeqId, null)
        requested = quantityRequestedByProduct.get(productId) ?: 0 as Double
        cancelQuantity = orderItem.getDouble('cancelQuantity')
        quantity = orderItem.getDouble('quantity')
        requested += quantity.doubleValue() - (cancelQuantity ? cancelQuantity.doubleValue() : 0)
        quantityRequestedByProduct.put(productId, requested)
    }
}

// for each package, we want to list the quantities and details of each product
packages = [] // note we assume that the package number is simply the index + 1 of this list
shipmentPackages.each { shipmentPackage ->
    contents = shipmentPackage.getRelated('ShipmentPackageContent', null, ['shipmentItemSeqId'], false)

    // each line is one logical Product and the quantities associated with it
    lines = []
    contents.each { content ->
        shipmentItem = content.getRelatedOne('ShipmentItem', false)
        product = shipmentItem.getRelatedOne('Product', false)
        productTypeId = product.get('productTypeId')

        line = [:]
        line.product = product
        line.quantityRequested = quantityRequestedByProduct.get(product.productId)
        line.quantityInPackage = content.quantity
        if (EntityTypeUtil.hasParentType(delegator, 'ProductType', 'productTypeId', productTypeId, 'parentTypeId', 'MARKETING_PKG_PICK')
                && line.quantityInPackage > line.quantityRequested) {
            line.quantityInPackage = line.quantityRequested
        }
        line.quantityInShipment = quantityInShipmentByProduct.get(product.productId)
        if (EntityTypeUtil.hasParentType(delegator, 'ProductType', 'productTypeId', productTypeId, 'parentTypeId', 'MARKETING_PKG_PICK')
                && line.quantityInShipment > line.quantityRequested) {
            line.quantityInShipment = line.quantityRequested
        }
        line.quantityShipped = quantityShippedByProduct.get(product.productId)
        if (EntityTypeUtil.hasParentType(delegator, 'ProductType', 'productTypeId', productTypeId, 'parentTypeId', 'MARKETING_PKG_PICK')
                && line.quantityShipped > line.quantityRequested) {
            line.quantityShipped = line.quantityRequested
        }
        lines.add(line)
    }
    packages.add(lines)
}
context.packages = packages
