package com.gridnine.xtrip.server.reports.templates

import com.gridnine.xtrip.common.Environment;
import com.gridnine.xtrip.common.model.entity.EntityStorage;
import com.gridnine.xtrip.common.model.EntityContainer;
import com.gridnine.xtrip.common.util.TextUtil;
import com.gridnine.xtrip.common.model.booking.ProductStatus;
import com.gridnine.xtrip.common.model.booking.BookingFile;
import com.gridnine.xtrip.common.model.booking.air.Product;
import java.util.*
import java.io.*
import java.math.*
import java.lang.*
import java.text.*
import com.gridnine.xtrip.common.gds.model.DailySalesReportItem;
import com.gridnine.xtrip.common.gds.model.BaseGdsAccount;

import com.gridnine.xtrip.common.model.booking.PassengerType;
import com.gridnine.xtrip.common.model.EntityReference;
import com.gridnine.xtrip.common.model.helpers.BookingHelper;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import com.gridnine.xtrip.common.model.system.DownloadableData
import com.gridnine.xtrip.common.parsers.model.RegistryParsingResult;
import com.gridnine.xtrip.common.parsers.model.RegistryRow;
import com.gridnine.xtrip.common.model.profile.Organization;
import com.gridnine.xtrip.common.model.helpers.AirProductTaxHelper;
import com.gridnine.xtrip.common.model.helpers.AirProductHelper;
import com.gridnine.xtrip.common.model.dict.ProductCategory;
import com.gridnine.xtrip.common.model.dict.MCOCategory;
import com.gridnine.xtrip.common.model.booking.commission.ProductType;
import com.gridnine.xtrip.common.model.booking.ProductIndex
//FROM config/server/setup/update.xml
createStyle(name: 'title',fontBold: true, h_span: 14, h_alignment: 'CENTER', v_alignment: 'CENTER', fontHeight:20)
createStyle(name: 'header',fontBold: false,  h_alignment: 'CENTER', v_alignment: 'CENTER', fontHeight:10, leftBorder:'MEDIUM', rightBorder:'MEDIUM', topBorder:'MEDIUM', bottomBorder:'MEDIUM', wrapText: true)
createStyle(name: 'data',fontBold: false,  h_alignment: 'CENTER', v_alignment: 'CENTER', fontHeight:10, leftBorder:'THIN', rightBorder:'THIN', topBorder:'THIN', bottomBorder:'THIN')
createStyle(name: 'textData',parent: 'data')
createStyle(name: 'error', parent: 'data', foreground: 'YELLOW')

def es = EntityStorage.get();
def dateBegin = parameters['key-report-params']['periodBegin']
def dateEnd = parameters['key-report-params']['periodEnd']
def reportDateBegin = new java.text.SimpleDateFormat("dd.MM.yyyy").format(dateBegin);
def reportDateEnd = new java.text.SimpleDateFormat("dd.MM.yyyy").format(dateEnd);
def clients = parameters['client']
DownloadableData sofiData = (DownloadableData) parameters['sofiFile']

Workbook wb = null;
InputStream is = new ByteArrayInputStream(sofiData.getContent().getData());
try {
    POIFSFileSystem fs = new POIFSFileSystem(is);
    wb = new HSSFWorkbook(fs);
} finally {
    is.close();
}

RegistryParsingResult voidData = parseWorkbook(wb, "ANN");
RegistryParsingResult sellData = parseWorkbook(wb, "SALE");
RegistryParsingResult refundData = parseWorkbook(wb, "RETURN");

Map momVoidData = [:]
Map momSaleData = [:]
Map momRefundData = [:]
Set<String> conjCountTickets = new HashSet<String>();
tickets{ ProductIndex productIndex ->	
	switch (productIndex.status){
		case ProductStatus.SELL:
		    productIndex.ticketNumbers.eachWithIndex {ticketNumber, index->
				if (index!=0){
					conjCountTickets.add(ticketNumber);
				}
				momSaleData[ticketNumber] = productIndex
			}				    
		    break
		case  ProductStatus.REFUND:
    		productIndex.ticketNumbers.eachWithIndex {ticketNumber, index->
    			if (index!=0){
    				conjCountTickets.add(ticketNumber);
    			}
    			momRefundData[ticketNumber] = productIndex
    		}		
		    break
		case  ProductStatus.VOID:  
		        momVoidData<<productIndex.ticketNumbers.collectEntries(it.ticketNumber, it)		  	
		    break
	}

}

createSheet('ANN');
text('Сверка аннуляции авиа билетов с СОФИ за ' + reportDateBegin + ' - ' + reportDateEnd, 'title')
2.times{nextRow()}

text('Номер билета', 'header')
columnWidth(35)
nextColumn()

for (RegistryRow row : voidData.getRows()) {
    Object ticketNumObj = row.getValue(2);
    String ticketNum;
    if (ticketNumObj instanceof BigDecimal) {
        BigDecimal res = (BigDecimal) ticketNumObj;
        ticketNum = res.setScale(0, RoundingMode.HALF_UP).toBigInteger().toString()
    } else {
        ticketNum = (String) ticketNumObj;
    }
    if (ticketNum != null && !TextUtil.isBlank(ticketNum.trim())) {
        nextRow();
        def momItem = momVoidData[ticketNum];
        String momTicketNum = momItem != null ? ticketNum : null;
        printText(ticketNum, momTicketNum);
        if (momItem != null) {
            momVoidData.remove(ticketNum);
        }
    }
}

momVoidData.each {
    nextRow();
    def ticketNumber = it.key;
    printText(null, ticketNumber);
}

createSheet('SALE');
text('Сверка продажи авиа билетов с СОФИ за ' + reportDateBegin + ' - ' + reportDateEnd, 'title')
2.times{nextRow()}

text('Номер билета', 'header')
columnWidth(35)
nextColumn()
text('Сумма к распределению (тариф)', 'header')
columnWidth(25)
nextColumn()
text('Сбор за несв. Отказ от полета', 'header')
columnWidth(25)
nextColumn()
text('АГС, TH', 'header')
columnWidth(25)
nextColumn()
text('Такса ZZ', 'header')
columnWidth(25)
nextColumn()
text('Дата продажи', 'header')
columnWidth(25)
nextColumn()
text('Фактические сборы', 'header')
columnWidth(25)
nextColumn()
text('Организация', 'header')
columnWidth(40)
rowHeight(40)

for (RegistryRow row : sellData.getRows()) {
    if (row.getValues().size() >= 35) {
        String org = row.getValue(34);
        if (org != null) {
            nextRow();
            String ticketNum = row.getValue(2).trim();
            ticketNum = ticketNum.substring(ticketNum.lastIndexOf(' ') + 1);
            BigDecimal price = row.getValue(7);
            BigDecimal penalty = row.getValue(8);
            String issueDate = row.getValue(15);
            BigDecimal fees = row.getValue(32);
            BigDecimal taxesOtherSum = row.getValue(9);
            BigDecimal taxesForBlankSum = row.getValue(10);
                                
            ProductIndex momItem = momSaleData[ticketNum];
            String momTicketNum = momItem != null ? ticketNum : null;
            BigDecimal momPrice = null;
            String momIssueDate = null;
            BigDecimal momFees = null;
            BigDecimal momPenalty = null;
            BigDecimal momTaxesOtherSum = null;
            BigDecimal momTaxesForBlankSum = null;
            if (momItem != null) {
                if (conjCountTickets.contains(momTicketNum)) {
                    momPrice = BigDecimal.ZERO;
                    momFees = BigDecimal.ZERO;
                    momTaxesForBlankSum = BigDecimal.ZERO;
                    momTaxesOtherSum = BigDecimal.ZERO;
                    momPenalty = BigDecimal.ZERO;
                } else {
                   // if (checkAirProductType(momItem.productType)) {
                        EntityContainer<BookingFile> bfCtr = EntityStorage.get().resolve(momItem.getSource());
                        Product p = (Product) BookingHelper.findProduct(bfCtr.getEntity(), momItem.getNavigationKey());
                        if (p.getProductCategory() == ProductCategory.MCO) {
                            momPrice = BigDecimal.ZERO;
                            if (p.getMcoCategory() == MCOCategory.PENALTY) {
                                momPenalty = momItem.penalty;
                            } else {
                                momPenalty = momItem.equivalentFare;
                            }
                        } else {
                            momPrice = calcSaleProductEquivalentFare(momItem, p);
                            momPenalty = calcSaleProductPenalty(momItem, p);
                        }
                        momFees = calcClientFee(momItem);
                        momTaxesForBlankSum = calcBookingTaxes(p);
                        momTaxesOtherSum = calcTaxesSum(momItem, p).subtract(momTaxesForBlankSum);
                 /*   } else {
                        momPrice = momItem.equivalentFare;
                        momPenalty = momItem.penalty != null ? momItem.penalty : BigDecimal.ZERO;
                        momFees = calcClientFee(momItem);
                        momTaxesForBlankSum = BigDecimal.ZERO;
                        momTaxesOtherSum = BigDecimal.ZERO;
                    }*/
                }
                momIssueDate = formatDate(momItem.issueDate);
                momSaleData.remove(ticketNum);
            }
                
            printText(ticketNum, momTicketNum);
            nextColumn();
            printText(formatBigDecimal(price), formatBigDecimal(momPrice));
            nextColumn();
            printText(formatBigDecimal(penalty), formatBigDecimal(momPenalty));
            nextColumn();
            printText(formatBigDecimal(taxesOtherSum), formatBigDecimal(momTaxesOtherSum));
            nextColumn();
            printText(formatBigDecimal(taxesForBlankSum), formatBigDecimal(momTaxesForBlankSum));
            nextColumn();
            printText(issueDate, momIssueDate);
            nextColumn();
            printText(formatBigDecimal(fees), formatBigDecimal(momFees));
            nextColumn();
            text(org, 'textData');
        }
    }
}


momSaleData.each { String ticketNumber, ProductIndex ticket ->
	
    nextRow();  
    printText(null, ticketNumber);
    nextColumn();
    BigDecimal momPrice = BigDecimal.ZERO;
    BigDecimal momPenalty = BigDecimal.ZERO;
    BigDecimal momFees = BigDecimal.ZERO;
    BigDecimal momTaxesOtherSum = BigDecimal.ZERO;
    BigDecimal momTaxesForBlankSum = BigDecimal.ZERO;

    if (!conjCountTickets.contains(ticketNumber)) {
       // if (checkAirProductType(ticket.productType)) {
            EntityContainer<BookingFile> bfCtr = EntityStorage.get().resolve(ticket.getSource());
            Product p = (Product) BookingHelper.findProduct(bfCtr.getEntity(), ticket.getNavigationKey());
            if (p.getProductCategory() == ProductCategory.MCO) {
                momPrice = BigDecimal.ZERO;
                if (p.getMcoCategory() == MCOCategory.PENALTY) {
                    momPenalty = ticket.penalty;
                } else {
                    momPenalty = ticket.equivalentFare;
                }
            } else {
                momPrice = calcSaleProductEquivalentFare(ticket, p);
                momPenalty = calcSaleProductPenalty(ticket, p);
            }
            momFees = calcClientFee(ticket);
            momTaxesForBlankSum = calcBookingTaxes(p);
            momTaxesOtherSum = calcTaxesSum(ticket, p).subtract(momTaxesForBlankSum);
       /* } else {
            momPrice = ticket.equivalentFare;
            momPenalty = ticket.penalty != null ? ticket.penalty : BigDecimal.ZERO;
            momFees = calcClientFee(ticket);
            momTaxesForBlankSum = BigDecimal.ZERO;
            momTaxesOtherSum = BigDecimal.ZERO;
        }*/
    }

    printText(null, formatBigDecimal(momPrice));
    nextColumn();
    printText(null, formatBigDecimal(momPenalty));
    nextColumn();
    printText(null, formatBigDecimal(momTaxesOtherSum));
    nextColumn();
    printText(null, formatBigDecimal(momTaxesForBlankSum));
    nextColumn();
    printText(null, formatDate(ticket.issueDate));
    nextColumn();
    printText(null, formatBigDecimal(momFees));
    nextColumn();
    printText(null, ticket.client.toString());
}



createSheet('RETURN');
text('Сверка возврата авиа билетов с СОФИ за ' + reportDateBegin + ' - ' + reportDateEnd, 'title')
2.times{nextRow()}

text('Номер билета', 'header')
columnWidth(35)
nextColumn()
text('Сумма к распределению (тариф)', 'header')
columnWidth(25)
nextColumn()
text('Сбор за несв. отказ от полета', 'header')
columnWidth(25)
nextColumn()
text('АГС, TH', 'header')
columnWidth(25)
nextColumn()
text('Такса ZZ', 'header')
columnWidth(25)
nextColumn()
text('Дата возврата', 'header')
columnWidth(25)
nextColumn()
text('Фактические сборы', 'header')
columnWidth(25)
nextColumn()
text('Организация', 'header')
columnWidth(40)
rowHeight(40)

for (RegistryRow row : refundData.getRows()) {
    if (row.getValues().size() >= 35) {
        String org = row.getValue(34);
        if (org != null) {
            nextRow();
            String ticketNum = row.getValue(2).trim();
            ticketNum = ticketNum.substring(ticketNum.lastIndexOf(' ') + 1);
            BigDecimal price = row.getValue(7);
            BigDecimal penalty = row.getValue(8);
            String issueDate = row.getValue(15);
            BigDecimal fees = row.getValue(32);
            BigDecimal taxesOtherSum = row.getValue(9);
            BigDecimal taxesForBlankSum = row.getValue(10);
            BigDecimal momTaxesOtherSum = null;
            BigDecimal momTaxesForBlankSum = null;
                                            
            ProductIndex momItem = momRefundData[ticketNum];
            String momTicketNum = momItem != null ? ticketNum : null;
            BigDecimal momPrice = null;
            BigDecimal momPenalty = null;
            String momIssueDate = null;
            BigDecimal momFees = null;
            if (momItem != null) {
                if (conjCountTickets.contains(momTicketNum)) {
                    momPrice = BigDecimal.ZERO;
                    momPenalty = BigDecimal.ZERO;
                    momFees = BigDecimal.ZERO;
                    momTaxesForBlankSum = BigDecimal.ZERO;
                    momTaxesOtherSum = BigDecimal.ZERO;
                } else {
                   // if (checkAirProductType(momItem.productType)) {
                        EntityContainer<BookingFile> bfCtr = EntityStorage.get().resolve(momItem.getSource());
                        Product p = (Product) BookingHelper.findProduct(bfCtr.getEntity(), momItem.getNavigationKey());
                        momPrice = momItem.equivalentFare != null ? momItem.equivalentFare.abs() : BigDecimal.ZERO;
                        momPenalty = momItem.penalty;
                        if (momPenalty != null) {
                            momPenalty = momPenalty.negate();
                        } else {
                            momPenalty = BigDecimal.ZERO;
                        }
                        momFees = calcClientFee(momItem);
                        momTaxesForBlankSum = calcBookingTaxes(p);
                        if (momItem.taxesSum != null) {
                            momTaxesOtherSum = momItem.taxesSum.abs().subtract(momTaxesForBlankSum);
                        }
                  /*  } else {
                        momPrice = momItem.equivalentFare.abs();
                        momPenalty = momItem.penalty != null ? momItem.penalty.negate() : BigDecimal.ZERO;
                        momFees = calcClientFee(momItem);
                        momTaxesForBlankSum = BigDecimal.ZERO;
                        momTaxesOtherSum = BigDecimal.ZERO;
                    }*/
                }
                momIssueDate = formatDate(momItem.issueDate);
                momRefundData.remove(ticketNum);
            }
                    
            printText(ticketNum, momTicketNum);
            nextColumn();
            printText(formatBigDecimal(price), formatBigDecimal(momPrice));
            nextColumn();
            printText(formatBigDecimal(penalty), formatBigDecimal(momPenalty));
            nextColumn();
            printText(formatBigDecimal(taxesOtherSum), formatBigDecimal(momTaxesOtherSum));
            nextColumn();
            printText(formatBigDecimal(taxesForBlankSum), formatBigDecimal(momTaxesForBlankSum));
            nextColumn();
            printText(issueDate, momIssueDate);
            nextColumn();
            printText(formatBigDecimal(fees), formatBigDecimal(momFees));
            nextColumn();
            text(org, 'textData');
        }
    }
}

momRefundData.each {String ticketNumber, ProductIndex ticket ->
    nextRow(); 
    printText(null, ticketNumber);
    nextColumn();
    BigDecimal momPrice = ticket.equivalentFare != null ? ticket.equivalentFare.abs() : BigDecimal.ZERO;
    BigDecimal momPenalty = BigDecimal.ZERO;
    BigDecimal momFees = BigDecimal.ZERO;
    BigDecimal momTaxesOtherSum = BigDecimal.ZERO;
    BigDecimal momTaxesForBlankSum = BigDecimal.ZERO;
    if (!conjCountTickets.contains(ticketNumber)) {
       // if (checkAirProductType(ticket.productType)) {
            if (ticket.penalty != null) {
                momPenalty = ticket.penalty.negate();
            }
            momTaxesForBlankSum = calcBookingTaxes(ticket);
            if (ticket.taxesSum != null) {
                momTaxesOtherSum = ticket.taxesSum.abs().subtract(momTaxesForBlankSum);
            }
            momFees = calcClientFee(ticket);
   /*     } else {
            momPrice = ticket.equivalentFare.abs();
            momPenalty = ticket.penalty != null ? ticket.penalty.negate() : BigDecimal.ZERO;
            momFees = calcClientFee(ticket);
            momTaxesForBlankSum = BigDecimal.ZERO;
            momTaxesOtherSum = BigDecimal.ZERO;
        }*/
    }
    printText(null, formatBigDecimal(momPrice));
    nextColumn();
    printText(null, formatBigDecimal(momPenalty));
    nextColumn();
    printText(null, formatBigDecimal(momTaxesOtherSum));
    nextColumn();
    printText(null, formatBigDecimal(momTaxesForBlankSum));
    nextColumn();
    printText(null, formatDate(ticket.issueDate));
    nextColumn();
    printText(null, formatBigDecimal(momFees));
    nextColumn();
    printText(null, ticket.client.toString());
}

RegistryParsingResult parseWorkbook(Workbook wb, String sheetName) {
    RegistryParsingResult result = new RegistryParsingResult();
    int startingRow = 13;
    int startingColumn = 0;
    for (Iterator<Row> rowIt = wb.getSheet(sheetName).rowIterator(); rowIt.hasNext();) {
        Row row = rowIt.next();
        if (row.getRowNum() < startingRow) {
            continue;
        }
        final List<Object> values = new LinkedList<Object>();
        for (Iterator<Cell> columnIt = row.cellIterator(); columnIt.hasNext();) {
            Cell cell = columnIt.next();
            if (cell.getColumnIndex() < startingColumn) {
                continue;
            }
            Object value = null;
            if (cell.getCellType() == Cell.CELL_TYPE_STRING) {
                value = cell.getRichStringCellValue().getString();
            } else if (cell.getCellType() == Cell.CELL_TYPE_BOOLEAN) {
                value = Boolean.valueOf(cell.getBooleanCellValue());
            } else if (cell.getCellType() == Cell.CELL_TYPE_NUMERIC) {
                if (isDate(cell.getCellStyle())) {
                    value = cell.getDateCellValue();
                } else {
                    value = BigDecimal.valueOf(cell.getNumericCellValue());
                }
            }
            int delta = cell.getColumnIndex() - startingColumn;
            int size = values.size();
            for (int n = size; n < delta; n++) {
                values.add(null);
            }
            values.add(value);
        }
        RegistryRow registryRow = new RegistryRow();
        registryRow.getValues().addAll(values);
        result.getRows().add(registryRow);
    }
    return result;
}

BigDecimal calcClientFee(ProductIndex idx) {
    BigDecimal res = BigDecimal.ZERO;
    if (idx.clientFeeValue != null) {
        res = res.add(idx.clientFeeValue);
    }
    if (idx.subagencyFeeValue != null) {
        res = res.subtract(idx.subagencyFeeValue);
    }
    return res;
}

boolean isDate(CellStyle cellStyle) {
    return ((cellStyle != null) && (cellStyle.getDataFormatString() != null)) && (cellStyle.getDataFormatString().contains(".") || cellStyle.getDataFormatString().contains("/")) && !cellStyle.getDataFormatString().contains("##");
}

String formatBigDecimal(BigDecimal value) {
    if (value == null) {
        return null;
    }
    value = value.setScale(2, BigDecimal.ROUND_HALF_UP);
    return value.toString();
}

void printText(Object obj1, Object obj2) {
    String text1 = obj1 != null ? obj1.toString() : "---";
    String text2 = obj2 != null ? obj2.toString() : "---";
    def fmt = text1.equals(text2) ? 'textData' : 'error'
    text(text1 + " / " + text2, fmt);
}

String formatDate(Date date) {
    if (date == null) {
        return null
    }
    DateFormat df = new SimpleDateFormat("dd.MM.yy");
    return df.format(date);
}

BigDecimal calcBookingTaxes(ProductIndex idx) {
    EntityContainer<BookingFile> bfCtr = EntityStorage.get().resolve(idx.getSource());
    if (bfCtr == null) {
        return BigDecimal.ZERO;
    }
    Product p = (Product) BookingHelper.findProduct(bfCtr.getEntity(), idx.getNavigationKey());
    return calcBookingTaxes(p);
}

BigDecimal calcBookingTaxes(Product product) {
    boolean returnAddCollect = ((product.getStatus() == ProductStatus.SELL)
                && (product.getPreviousProduct() != null) && (product
                .getPreviousProduct().getStatus() == ProductStatus.EXCHANGE));
    if (returnAddCollect) {
        BigDecimal res = AirProductTaxHelper.getAddCollectTaxesAmountByCodes(product.getTaxes(), true, AirProductTaxHelper.getTaxesForBlankCodes(product.getCarrier()));
        res = res.add(AirProductTaxHelper.getAddCollectTaxesAmountByCodes(product.getTaxes(), true, AirProductTaxHelper.getTaxesForGDSCodes(product.getCarrier())));
        BigDecimal ruTaxes = AirProductTaxHelper.getEquivalentTaxesAmountByCodes(product.getTaxes(), true, "РУ");
        if (ruTaxes.compareTo(BigDecimal.ZERO) == 0) {
            res = res.add(AirProductTaxHelper.getAddCollectTaxesAmountByCodes(product.getTaxes(), true, "SA"));
        }
        return res;
    }
    BigDecimal res = AirProductTaxHelper.getEquivalentTaxesAmountByCodes(product, AirProductTaxHelper.getTaxesForBlankCodes(product.getCarrier()));
    res = res.add(AirProductTaxHelper.getEquivalentTaxesAmountByCodes(product, AirProductTaxHelper.getTaxesForGDSCodes(product.getCarrier())));
    BigDecimal ruTaxes = AirProductTaxHelper.getEquivalentTaxesAmountByCodes(product.getTaxes(), true, "РУ");
    if (ruTaxes.compareTo(BigDecimal.ZERO) == 0) {
        res = res.add(AirProductTaxHelper.getEquivalentTaxesAmountByCodes(product, "SA"));
    }
    return res;
}

BigDecimal calcTaxesSum(ProductIndex idx, Product product) {
    boolean returnAddCollect = ((product.getStatus() == ProductStatus.SELL)
                && (product.getPreviousProduct() != null) && (product
                .getPreviousProduct().getStatus() == ProductStatus.EXCHANGE));
    if (returnAddCollect) {
        BigDecimal res = AirProductHelper.calculateTaxesEquivalentAddCollect(product);
        if (res != null) {
            res = res.subtract(AirProductTaxHelper.getAddCollectTaxesAmountByCodes(product.getTaxes(), true, "CP", "OD", "DL"));
        }
        return res == null ? BigDecimal.ZERO : res;
    }
    BigDecimal res = idx.taxesSum;
    if (res != null) {
        res = res.subtract(AirProductTaxHelper.getEquivalentTaxesAmountByCodes(product, "CP", "OD", "DL"));
    }
    return res;
}

BigDecimal calcSaleProductEquivalentFare(ProductIndex idx, Product product) {
    boolean returnAddCollect = ((product.getStatus() == ProductStatus.SELL)
                && (product.getPreviousProduct() != null) && (product
                .getPreviousProduct().getStatus() == ProductStatus.EXCHANGE));
    if (returnAddCollect) {
        return product.getAddCollectEquivalent() != null ? product.getAddCollectEquivalent() : BigDecimal.ZERO;
    }
    return idx.equivalentFare;
}

BigDecimal calcSaleProductPenalty(ProductIndex idx, Product product) {
    BigDecimal res = idx.penalty != null ? idx.penalty : BigDecimal.ZERO;
    res = res.add(AirProductTaxHelper.getEquivalentTaxesAmountByCodes(product, "CP", "OD", "DL"));
    return res;
}

boolean checkAirProductType(ProductType productType) {
    return productType != null && (productType == ProductType.AIR_TICKET || productType.name().startsWith("MCO"));
}


