/*
 * The Kuali Financial System, a comprehensive financial management system for higher education.
 *
 * Copyright 2005-2016 The Kuali Foundation
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.kuali.kfs.module.ld.batch.service.impl;

import org.apache.commons.lang.StringUtils;
import org.kuali.kfs.coreservice.framework.parameter.ParameterService;
import org.kuali.kfs.gl.GeneralLedgerConstants;
import org.kuali.kfs.gl.batch.service.PostTransaction;
import org.kuali.kfs.gl.batch.service.VerifyTransaction;
import org.kuali.kfs.gl.report.LedgerSummaryReport;
import org.kuali.kfs.gl.report.TransactionListingReport;
import org.kuali.kfs.gl.service.OriginEntryGroupService;
import org.kuali.kfs.krad.util.ObjectUtils;
import org.kuali.kfs.module.ld.LaborConstants;
import org.kuali.kfs.module.ld.LaborConstants.Poster;
import org.kuali.kfs.module.ld.batch.LaborPosterStep;
import org.kuali.kfs.module.ld.batch.service.LaborPosterService;
import org.kuali.kfs.module.ld.businessobject.LaborOriginEntry;
import org.kuali.kfs.module.ld.document.validation.impl.TransactionFieldValidator;
import org.kuali.kfs.module.ld.service.LaborOriginEntryService;
import org.kuali.kfs.module.ld.service.LaborTransactionDescriptionService;
import org.kuali.kfs.module.ld.util.LaborLedgerUnitOfWork;
import org.kuali.kfs.module.ld.util.LaborOriginEntryFileIterator;
import org.kuali.kfs.sys.KFSConstants;
import org.kuali.kfs.sys.Message;
import org.kuali.kfs.sys.MessageBuilder;
import org.kuali.kfs.sys.service.ReportWriterService;
import org.kuali.rice.core.api.datetime.DateTimeService;
import org.springframework.transaction.annotation.Transactional;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintStream;
import java.sql.Date;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static org.kuali.kfs.module.ld.LaborConstants.DestinationNames.ORIGN_ENTRY;

/**
 * The Labor Ledger Poster accepts pending entries generated by Labor Ledger e-docs (such as Salary Expense Transfer and Benefit
 * Expense Transfer), and combines them with entries from external systems. It edits the entries for validity. Invalid entries can
 * be marked for Labor Ledger Error Correction process. The Poster writes valid entries to the Labor Ledger Entry table, updates
 * balances in the Labor Ledger Balance table, and summarizes the entries for posting to the General Ledger.
 */
@Transactional
public class LaborPosterServiceImpl implements LaborPosterService {
    private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(LaborPosterServiceImpl.class);

    protected LaborOriginEntryService laborOriginEntryService;
    protected OriginEntryGroupService originEntryGroupService;
    protected LaborTransactionDescriptionService laborTransactionDescriptionService;

    protected ReportWriterService reportWriterService;
    protected ReportWriterService errorListingReportWriterService;
    protected ReportWriterService ledgerSummaryReportWriterService;
    protected ReportWriterService laborGlEntryStatisticsReportWriterService;

    protected DateTimeService dateTimeService;
    protected VerifyTransaction laborPosterTransactionValidator;
    protected ParameterService parameterService;

    protected PostTransaction laborLedgerEntryPoster;
    protected PostTransaction laborLedgerBalancePoster;
    protected PostTransaction laborGLLedgerEntryPoster;

    protected int numberOfErrorOriginEntry;

    protected String batchFileDirectoryName;
    protected PrintStream POSTER_OUTPUT_ERR_FILE_ps;

    /**
     * @see org.kuali.kfs.module.ld.batch.service.LaborPosterService#postMainEntries()
     */
    public void postMainEntries() {
        LOG.debug("postMainEntries() started");

        Date runDate = dateTimeService.getCurrentSqlDate();
        this.postLaborLedgerEntries(runDate);
    }

    /**
     * post the qualified origin entries into Labor Ledger tables
     *
     * @param validGroup   the origin entry group that holds the valid transactions
     * @param invalidGroup the origin entry group that holds the invalid transactions
     * @param runDate      the data when the process is running
     */
    protected void postLaborLedgerEntries(Date runDate) {
        LOG.debug("postLaborLedgerEntries() started..........................");
        numberOfErrorOriginEntry = 0;
        // change file name to FIS

        String postInputFileName = batchFileDirectoryName + File.separator + LaborConstants.BatchFileSystem.POSTER_INPUT_FILE + GeneralLedgerConstants.BatchFileSystem.EXTENSION;
        String postErrFileName = batchFileDirectoryName + File.separator + LaborConstants.BatchFileSystem.POSTER_ERROR_OUTPUT_FILE + GeneralLedgerConstants.BatchFileSystem.EXTENSION;

        FileReader INPUT_GLE_FILE = null;
        try {
            INPUT_GLE_FILE = new FileReader(postInputFileName);
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        }

        try {
            POSTER_OUTPUT_ERR_FILE_ps = new PrintStream(postErrFileName);
        } catch (IOException e) {
            LOG.error("postLaborLedgerEntries cannot open file: " + e.getMessage(), e);
            throw new RuntimeException(e);
        }

        int lineNumber = 0;
        int loadedCount = 0;

        int numberOfSelectedOriginEntry = 0;
        LaborLedgerUnitOfWork laborLedgerUnitOfWork = new LaborLedgerUnitOfWork();

        LedgerSummaryReport ledgerSummaryReport = new LedgerSummaryReport();

        Map<String, Integer> reportSummary = this.constructPosterReportSummary();
        Map<String, Integer> glEntryReportSummary = this.constructGlEntryReportSummary();

        try {
            BufferedReader INPUT_GLE_FILE_br = new BufferedReader(INPUT_GLE_FILE);
            String currentLine = INPUT_GLE_FILE_br.readLine();

            while (currentLine != null) {
                LaborOriginEntry laborOriginEntry = null;

                try {
                    lineNumber++;
                    if (!StringUtils.isEmpty(currentLine) && !StringUtils.isBlank(currentLine.trim())) {
                        laborOriginEntry = new LaborOriginEntry();

                        // checking parsing process and stop poster when it has errors.
                        List<Message> parsingError = new ArrayList<Message>();
                        parsingError = laborOriginEntry.setFromTextFileForBatch(currentLine, lineNumber);
                        if (parsingError.size() > 0) {
                            throw new RuntimeException("Exception happened from parsing process");
                        }

                        loadedCount++;
                        if (loadedCount % 1000 == 0) {
                            LOG.info(loadedCount + " " + laborOriginEntry.toString());
                        }

                        boolean isPostable = this.postSingleEntryIntoLaborLedger(laborOriginEntry, reportSummary, runDate, currentLine);
                        if (isPostable) {
                            this.updateReportSummary(glEntryReportSummary, ORIGN_ENTRY, KFSConstants.OperationType.READ);
                            this.writeLaborGLEntry(laborOriginEntry, laborLedgerUnitOfWork, runDate, lineNumber, glEntryReportSummary);

                            ledgerSummaryReport.summarizeEntry(laborOriginEntry);

                            numberOfSelectedOriginEntry++;
                            laborOriginEntry = null;
                        }
                    }

                    currentLine = INPUT_GLE_FILE_br.readLine();
                } catch (RuntimeException re) {
                    // catch here again, it should be from postSingleEntryIntoLaborLedger
                    LOG.error("postLaborLedgerEntries stopped due to: " + re.getMessage() + " on line number : " + loadedCount, re);
                    LOG.error("laborOriginEntry failure occured on: " + laborOriginEntry == null ? null : laborOriginEntry.toString());
                    throw new RuntimeException("Unable to execute: " + re.getMessage() + " on line number : " + loadedCount, re);
                }
            }

            this.writeLaborGLEntry(null, laborLedgerUnitOfWork, runDate, lineNumber, glEntryReportSummary);

            INPUT_GLE_FILE_br.close();
            INPUT_GLE_FILE.close();
            POSTER_OUTPUT_ERR_FILE_ps.close();

            this.fillPosterReportWriter(lineNumber, reportSummary, glEntryReportSummary);
            this.fillGlEntryReportWriter(glEntryReportSummary);

            // Generate Error Listing Report
            ledgerSummaryReport.writeReport(ledgerSummaryReportWriterService);
            new TransactionListingReport().generateReport(errorListingReportWriterService, new LaborOriginEntryFileIterator(new File(postErrFileName)));
        } catch (IOException ioe) {
            LOG.error("postLaborLedgerEntries stopped due to: " + ioe.getMessage(), ioe);
            throw new RuntimeException("Unable to execute: " + ioe.getMessage() + " on line number : " + loadedCount, ioe);
        }
    }

    /**
     * post the given entry into the labor ledger tables if the entry is qualified; otherwise report error
     *
     * @param originEntry   the given origin entry, a transaction
     * @param reportSummary the report summary object that need to be update when a transaction is posted
     * @param runDate       the data when the process is running
     * @return true if the given transaction is posted into ledger tables; otherwise, return false
     */
    protected boolean postSingleEntryIntoLaborLedger(LaborOriginEntry originEntry, Map<String, Integer> reportSummary, Date runDate, String line) {
        // reject the invalid entry so that it can be available for error correction
        List<Message> errors = new ArrayList<Message>();
        try {
            errors = this.validateEntry(originEntry);
        } catch (Exception e) {
            errors.add(new Message(e.toString() + " occurred for this record.", Message.TYPE_FATAL));
        }

        if (errors != null && !errors.isEmpty()) {
            reportWriterService.writeError(originEntry, errors);
            numberOfErrorOriginEntry += errors.size();
            writeErrorEntry(line);
            return false;
        }

        String operationOnLedgerEntry = postAsLedgerEntry(originEntry, runDate);
        updateReportSummary(reportSummary, laborLedgerEntryPoster.getDestinationName(), operationOnLedgerEntry);

        String operationOnLedgerBalance = updateLedgerBalance(originEntry, runDate);
        updateReportSummary(reportSummary, laborLedgerBalancePoster.getDestinationName(), operationOnLedgerBalance);

        return true;
    }

    /**
     * validate the given entry, and generate an error list if the entry cannot meet the business rules
     *
     * @param originEntry the given origin entry, a transcation
     * @return error message list. If the given transaction is invalid, the list has message(s); otherwise, it is empty
     */
    protected List<Message> validateEntry(LaborOriginEntry originEntry) {
        return laborPosterTransactionValidator.verifyTransaction(originEntry);
    }

    /**
     * post the given entry to the labor entry table
     *
     * @param originEntry the given origin entry, a transaction
     * @param postDate    the data when the transaction is processes return the operation type of the process
     */
    protected String postAsLedgerEntry(LaborOriginEntry originEntry, Date postDate) {
        return laborLedgerEntryPoster.post(originEntry, 0, postDate, null);
    }

    /**
     * update the labor ledger balance for the given entry
     *
     * @param originEntry the given origin entry, a transaction
     * @param postDate    the data when the transaction is processes return the operation type of the process
     */
    protected String updateLedgerBalance(LaborOriginEntry originEntry, Date postDate) {
        return laborLedgerBalancePoster.post(originEntry, 0, postDate, null);
    }

    /**
     * determine if the given origin entry can be posted back to Labor GL entry
     *
     * @param originEntry the given origin entry, atransaction
     * @return a message list. The list has message(s) if the given origin entry cannot be posted back to Labor GL entry; otherwise,
     * it is empty
     */
    protected List<Message> isPostableForLaborGLEntry(LaborOriginEntry originEntry) {
        List<Message> errors = new ArrayList<Message>();
        MessageBuilder.addMessageIntoList(errors, TransactionFieldValidator.checkPostablePeridCode(originEntry, getPeriodCodesNotProcessed()));
        MessageBuilder.addMessageIntoList(errors, TransactionFieldValidator.checkPostableBalanceTypeCode(originEntry, getBalanceTypesNotProcessed()));
        MessageBuilder.addMessageIntoList(errors, TransactionFieldValidator.checkZeroTotalAmount(originEntry));
        return errors;
    }

    // construct a poster report summary object
    protected void fillPosterReportWriter(int lineNumber, Map<String, Integer> reportSummary, Map<String, Integer> glEntryReportSummary) {
        reportWriterService.writeStatisticLine("SEQUENTIAL RECORDS READ                    %,9d", lineNumber);
        reportWriterService.writeStatisticLine("LLEN RECORDS INSERTED (LD_LDGR_ENTR_T)     %,9d", reportSummary.get(laborLedgerEntryPoster.getDestinationName() + "," + KFSConstants.OperationType.INSERT));
        reportWriterService.writeStatisticLine("LLBL RECORDS INSERTED (LD_LDGR_BAL_T)      %,9d", reportSummary.get(laborLedgerBalancePoster.getDestinationName() + "," + KFSConstants.OperationType.INSERT));
        reportWriterService.writeStatisticLine("LLBL RECORDS UPDATED  (LD_LDGR_BAL_T)      %,9d", reportSummary.get(laborLedgerBalancePoster.getDestinationName() + "," + KFSConstants.OperationType.UPDATE));
        reportWriterService.writeStatisticLine("LLGL RECORDS INSERTED (LD_LBR_GL_ENTRY_T)  %,9d", glEntryReportSummary.get(laborGLLedgerEntryPoster.getDestinationName() + "," + KFSConstants.OperationType.INSERT));
        reportWriterService.writeStatisticLine("WARNING RECORDS WRITTEN                    %,9d", numberOfErrorOriginEntry);
    }

    // fill the poster report writer with the collected data
    protected Map<String, Integer> constructPosterReportSummary() {
        Map<String, Integer> reportSummary = new HashMap<String, Integer>();
        reportSummary.put(laborLedgerEntryPoster.getDestinationName() + "," + KFSConstants.OperationType.INSERT, 0);
        reportSummary.put(laborLedgerBalancePoster.getDestinationName() + "," + KFSConstants.OperationType.INSERT, 0);
        reportSummary.put(laborLedgerBalancePoster.getDestinationName() + "," + KFSConstants.OperationType.UPDATE, 0);
        reportSummary.put(laborGLLedgerEntryPoster.getDestinationName() + "," + KFSConstants.OperationType.INSERT, 0);
        return reportSummary;
    }

    // construct a gl entry report summary object
    protected Map<String, Integer> constructGlEntryReportSummary() {
        Map<String, Integer> glEntryReportSummary = new HashMap<String, Integer>();
        glEntryReportSummary.put(ORIGN_ENTRY + "," + KFSConstants.OperationType.READ, 0);
        glEntryReportSummary.put(ORIGN_ENTRY + "," + KFSConstants.OperationType.BYPASS, 0);
        glEntryReportSummary.put(ORIGN_ENTRY + "," + KFSConstants.OperationType.SELECT, 0);
        glEntryReportSummary.put(ORIGN_ENTRY + "," + KFSConstants.OperationType.REPORT_ERROR, 0);
        glEntryReportSummary.put(laborGLLedgerEntryPoster.getDestinationName() + "," + KFSConstants.OperationType.INSERT, 0);

        return glEntryReportSummary;
    }

    // fill the gl entry report writer with the collected data
    protected void fillGlEntryReportWriter(Map<String, Integer> glEntryReportSummary) {
        laborGlEntryStatisticsReportWriterService.writeStatisticLine("NUMBER OF RECORDS READ              %,9d", glEntryReportSummary.get(ORIGN_ENTRY + "," + KFSConstants.OperationType.READ));
        laborGlEntryStatisticsReportWriterService.writeStatisticLine("NUMBER OF RECORDS BYPASSED          %,9d", glEntryReportSummary.get(ORIGN_ENTRY + "," + KFSConstants.OperationType.BYPASS));
        laborGlEntryStatisticsReportWriterService.writeStatisticLine("NUMBER OF RECORDS SELECTED          %,9d", glEntryReportSummary.get(ORIGN_ENTRY + "," + KFSConstants.OperationType.SELECT));
        laborGlEntryStatisticsReportWriterService.writeStatisticLine("NUMBER OF RECORDS IN ERROR          %,9d", glEntryReportSummary.get(ORIGN_ENTRY + "," + KFSConstants.OperationType.REPORT_ERROR));
        laborGlEntryStatisticsReportWriterService.writeStatisticLine("NUMBER OF RECORDS INSERTED          %,9d", glEntryReportSummary.get(laborGLLedgerEntryPoster.getDestinationName() + "," + KFSConstants.OperationType.INSERT));
    }

    /**
     * summary the valid origin entries for the General Ledger
     *
     * @param laborOriginEntry      the current entry to check for summarization
     * @param laborLedgerUnitOfWork the current (in process) summarized entry for the GL
     * @param runDate               the data when the process is running
     * @param lineNumber            the line in the input file (used for error message only)
     */
    protected LaborOriginEntry summarizeLaborGLEntries(LaborOriginEntry laborOriginEntry, LaborLedgerUnitOfWork laborLedgerUnitOfWork, Date runDate, int lineNumber, Map<String, Integer> glEntryReportSummary) {
        // KFSMI-5308: Description update moved here due to requirement for this to happen before consolidation
        if (ObjectUtils.isNotNull(laborOriginEntry)) {
            String description = laborTransactionDescriptionService.getTransactionDescription(laborOriginEntry);
            if (StringUtils.isNotEmpty(description)) {
                laborOriginEntry.setTransactionLedgerEntryDescription(description);
            }
        }

        LaborOriginEntry summarizedEntry = null;
        if (laborLedgerUnitOfWork.canContain(laborOriginEntry)) {
            laborLedgerUnitOfWork.addEntryIntoUnit(laborOriginEntry);
            updateReportSummary(glEntryReportSummary, ORIGN_ENTRY, KFSConstants.OperationType.SELECT);
        } else {
            summarizedEntry = laborLedgerUnitOfWork.getWorkingEntry();
            laborLedgerUnitOfWork.resetLaborLedgerUnitOfWork(laborOriginEntry);
        }

        return summarizedEntry;
    }

    protected void writeLaborGLEntry(LaborOriginEntry laborOriginEntry, LaborLedgerUnitOfWork laborLedgerUnitOfWork, Date runDate, int lineNumber, Map<String, Integer> glEntryReportSummary) {
        LaborOriginEntry summarizedEntry = summarizeLaborGLEntries(laborOriginEntry, laborLedgerUnitOfWork, runDate, lineNumber, glEntryReportSummary);
        if (summarizedEntry == null) {
            return;
        }

        try {
            List<Message> errors = this.isPostableForLaborGLEntry(summarizedEntry);
            if (errors == null || errors.isEmpty()) {
                String operationType = laborGLLedgerEntryPoster.post(summarizedEntry, 0, runDate, null);
                updateReportSummary(glEntryReportSummary, laborGLLedgerEntryPoster.getDestinationName(), operationType);
            } else {
                updateReportSummary(glEntryReportSummary, ORIGN_ENTRY, KFSConstants.OperationType.BYPASS);
            }
        } catch (RuntimeException ioe) {
            // catch here again, it should be from postSingleEntryIntoLaborLedger
            LOG.error("postLaborGLEntries stopped due to: " + ioe.getMessage() + " on line number : " + lineNumber, ioe);
            throw new RuntimeException("Unable to execute: " + ioe.getMessage() + " on line number : " + lineNumber, ioe);
        }
    }

    protected void updateReportSummary(Map<String, Integer> reportSummary, String destination, String operation) {
        String key = destination + "," + operation;

        if (reportSummary.containsKey(key)) {
            Integer count = reportSummary.get(key);
            reportSummary.put(key, count + 1);
        } else {
            reportSummary.put(key, 1);
        }
    }

    protected void writeErrorEntry(String line) {
        try {
            POSTER_OUTPUT_ERR_FILE_ps.printf("%s\n", line);
        } catch (Exception e) {
            LOG.error("postAsProcessedOriginEntry stopped due to: " + e.getMessage(), e);
            throw new RuntimeException("Unable to execute: " + e.getMessage(), e);
        }
    }

    /**
     * Get a set of the balance type codes that are bypassed by Labor Poster
     *
     * @return a set of the balance type codes that are bypassed by Labor Poster
     */
    public Collection<String> getBalanceTypesNotProcessed() {
        return parameterService.getParameterValuesAsString(LaborPosterStep.class, Poster.BALANCE_TYPES_NOT_PROCESSED);
    }

    /**
     * Get a set of the fiscal period codes that are bypassed by Labor Poster
     *
     * @return a set of the fiscal period codes that are bypassed by Labor Poster
     */
    public Collection<String> getPeriodCodesNotProcessed() {
        return parameterService.getParameterValuesAsString(LaborPosterStep.class, Poster.PERIOD_CODES_NOT_PROCESSED);
    }

    /**
     * Sets the dateTimeService attribute value.
     *
     * @param dateTimeService The dateTimeService to set.
     */
    public void setDateTimeService(DateTimeService dateTimeService) {
        this.dateTimeService = dateTimeService;
    }


    /**
     * Sets the laborLedgerBalancePoster attribute value.
     *
     * @param laborLedgerBalancePoster The laborLedgerBalancePoster to set.
     */
    public void setLaborLedgerBalancePoster(PostTransaction laborLedgerBalancePoster) {
        this.laborLedgerBalancePoster = laborLedgerBalancePoster;
    }

    /**
     * Sets the laborGLLedgerEntryPoster attribute value.
     *
     * @param laborGLLedgerEntryPoster The laborGLLedgerEntryPoster to set.
     */
    public void setLaborGLLedgerEntryPoster(PostTransaction laborGLLedgerEntryPoster) {
        this.laborGLLedgerEntryPoster = laborGLLedgerEntryPoster;
    }

    /**
     * Sets the laborLedgerEntryPoster attribute value.
     *
     * @param laborLedgerEntryPoster The laborLedgerEntryPoster to set.
     */
    public void setLaborLedgerEntryPoster(PostTransaction laborLedgerEntryPoster) {
        this.laborLedgerEntryPoster = laborLedgerEntryPoster;
    }

    /**
     * Sets the laborOriginEntryService attribute value.
     *
     * @param laborOriginEntryService The laborOriginEntryService to set.
     */
    public void setLaborOriginEntryService(LaborOriginEntryService laborOriginEntryService) {
        this.laborOriginEntryService = laborOriginEntryService;
    }

    /**
     * Sets the originEntryGroupService attribute value.
     *
     * @param originEntryGroupService The originEntryGroupService to set.
     */
    public void setOriginEntryGroupService(OriginEntryGroupService originEntryGroupService) {
        this.originEntryGroupService = originEntryGroupService;
    }

    /**
     * Sets the laborTransactionDescriptionService attribute value.
     *
     * @param laborTransactionDescriptionService The laborTransactionDescriptionService to set.
     */
    public void setLaborTransactionDescriptionService(LaborTransactionDescriptionService laborTransactionDescriptionService) {
        this.laborTransactionDescriptionService = laborTransactionDescriptionService;
    }

    /**
     * Sets the reportWriterService
     *
     * @param reportWriterService The reportWriterService to set.
     */
    public void setReportWriterService(ReportWriterService reportWriterService) {
        this.reportWriterService = reportWriterService;
    }

    /**
     * Sets the errorListingReportWriterService
     *
     * @param errorListingReportWriterService The errorListingReportWriterService to set.
     */
    public void setErrorListingReportWriterService(ReportWriterService errorListingReportWriterService) {
        this.errorListingReportWriterService = errorListingReportWriterService;
    }

    /**
     * Sets the ledgerSummaryReportWriterService
     *
     * @param ledgerSummaryReportWriterService The ledgerSummaryReportWriterService to set.
     */
    public void setLedgerSummaryReportWriterService(ReportWriterService ledgerSummaryReportWriterService) {
        this.ledgerSummaryReportWriterService = ledgerSummaryReportWriterService;
    }

    /**
     * Sets the laborPosterTransactionValidator attribute value.
     *
     * @param laborPosterTransactionValidator The laborPosterTransactionValidator to set.
     */
    public void setLaborPosterTransactionValidator(VerifyTransaction laborPosterTransactionValidator) {
        this.laborPosterTransactionValidator = laborPosterTransactionValidator;
    }

    /**
     * Sets the parameterService attribute value.
     *
     * @param parameterService The parameterService to set.
     */
    public void setParameterService(ParameterService parameterService) {
        this.parameterService = parameterService;
    }

    /**
     * Sets the laborGlEntryStatisticsReportWriterService attribute value.
     *
     * @param laborGlEntryStatisticsReportWriterService The laborGlEntryStatisticsReportWriterService to set.
     */
    public void setLaborGlEntryStatisticsReportWriterService(ReportWriterService laborGlEntryStatisticsReportWriterService) {
        this.laborGlEntryStatisticsReportWriterService = laborGlEntryStatisticsReportWriterService;
    }

    /**
     * Sets the batchFileDirectoryName attribute value.
     *
     * @param batchFileDirectoryName The batchFileDirectoryName to set.
     */
    public void setBatchFileDirectoryName(String batchFileDirectoryName) {
        this.batchFileDirectoryName = batchFileDirectoryName;
    }
}
