mirror of
				https://github.com/firefly-iii/firefly-iii.git
				synced 2025-11-04 05:15:39 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			215 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			215 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
<?php
 | 
						|
/**
 | 
						|
 * MappingConverger.php
 | 
						|
 * Copyright (c) 2018 thegrumpydictator@gmail.com
 | 
						|
 *
 | 
						|
 * This file is part of Firefly III.
 | 
						|
 *
 | 
						|
 * Firefly III is free software: you can redistribute it and/or modify
 | 
						|
 * it under the terms of the GNU General Public License as published by
 | 
						|
 * the Free Software Foundation, either version 3 of the License, or
 | 
						|
 * (at your option) any later version.
 | 
						|
 *
 | 
						|
 * Firefly III 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 General Public License for more details.
 | 
						|
 *
 | 
						|
 * You should have received a copy of the GNU General Public License
 | 
						|
 * along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
 | 
						|
 */
 | 
						|
 | 
						|
declare(strict_types=1);
 | 
						|
 | 
						|
namespace FireflyIII\Support\Import\Routine\File;
 | 
						|
 | 
						|
use FireflyIII\Exceptions\FireflyException;
 | 
						|
use FireflyIII\Models\ImportJob;
 | 
						|
use FireflyIII\Repositories\ImportJob\ImportJobRepositoryInterface;
 | 
						|
use FireflyIII\Support\Import\Placeholder\ColumnValue;
 | 
						|
use Log;
 | 
						|
 | 
						|
/**
 | 
						|
 * Class MappingConverger
 | 
						|
 */
 | 
						|
class MappingConverger
 | 
						|
{
 | 
						|
    /** @var array */
 | 
						|
    private $doMapping;
 | 
						|
    /** @var ImportJob */
 | 
						|
    private $importJob;
 | 
						|
    /** @var array */
 | 
						|
    private $mappedValues;
 | 
						|
    /** @var array */
 | 
						|
    private $mapping;
 | 
						|
    /** @var ImportJobRepositoryInterface */
 | 
						|
    private $repository;
 | 
						|
    /** @var array */
 | 
						|
    private $roles;
 | 
						|
 | 
						|
    /**
 | 
						|
     * Each cell in the CSV file could be linked to a mapped value. This depends on the role of
 | 
						|
     * the column and the content of the cell. This method goes over all cells, and using their
 | 
						|
     * associated role, will see if it has been linked to a mapped value. These mapped values
 | 
						|
     * are all IDs of objects in the Firefly III database.
 | 
						|
     *
 | 
						|
     * If such a mapping exists the role of the cell changes to whatever the mapped value is.
 | 
						|
     *
 | 
						|
     * Examples:
 | 
						|
     *
 | 
						|
     * - Cell with content "Checking Account" and role "account-name". Mapping links "Checking Account" to account-id 2.
 | 
						|
     * - Cell with content "Checking Account" and role "description". No mapping, so value and role remains the same.
 | 
						|
     *
 | 
						|
     * @param array $lines
 | 
						|
     *
 | 
						|
     * @return array
 | 
						|
     * @throws FireflyException
 | 
						|
     */
 | 
						|
    public function converge(array $lines): array
 | 
						|
    {
 | 
						|
        Log::debug('Start converging process.');
 | 
						|
        $collection = [];
 | 
						|
        $total      = count($lines);
 | 
						|
        /** @var array $line */
 | 
						|
        foreach ($lines as $lineIndex => $line) {
 | 
						|
            Log::debug(sprintf('Now converging line %d out of %d.', $lineIndex + 1, $total));
 | 
						|
            $set          = $this->processLine($line);
 | 
						|
            $collection[] = $set;
 | 
						|
        }
 | 
						|
 | 
						|
        return $collection;
 | 
						|
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * @codeCoverageIgnore
 | 
						|
     * @return array
 | 
						|
     */
 | 
						|
    public function getMappedValues(): array
 | 
						|
    {
 | 
						|
        return $this->mappedValues;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * @param ImportJob $importJob
 | 
						|
     */
 | 
						|
    public function setImportJob(ImportJob $importJob): void
 | 
						|
    {
 | 
						|
        $this->importJob  = $importJob;
 | 
						|
        $this->repository = app(ImportJobRepositoryInterface::class);
 | 
						|
        $this->repository->setUser($importJob->user);
 | 
						|
        $this->mappedValues = [];
 | 
						|
        $config             = $importJob->configuration;
 | 
						|
        $this->roles        = $config['column-roles'] ?? [];
 | 
						|
        $this->mapping      = $config['column-mapping-config'] ?? [];
 | 
						|
        $this->doMapping    = $config['column-do-mapping'] ?? [];
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * If the value in the column is mapped to a certain ID,
 | 
						|
     * the column where this ID must be placed will change.
 | 
						|
     *
 | 
						|
     * For example, if you map role "budget-name" with value "groceries" to 1,
 | 
						|
     * then that should become the budget-id. Not the name.
 | 
						|
     *
 | 
						|
     * @param int $column
 | 
						|
     * @param int $mapped
 | 
						|
     *
 | 
						|
     * @return string
 | 
						|
     * @throws FireflyException
 | 
						|
     */
 | 
						|
    private function getRoleForColumn(int $column, int $mapped): string
 | 
						|
    {
 | 
						|
        $role = $this->roles[$column] ?? '_ignore';
 | 
						|
        if (0 === $mapped) {
 | 
						|
            Log::debug(sprintf('Column #%d with role "%s" is not mapped.', $column, $role));
 | 
						|
 | 
						|
            return $role;
 | 
						|
        }
 | 
						|
        if (!(isset($this->doMapping[$column]) && true === $this->doMapping[$column])) {
 | 
						|
 | 
						|
            // if the mapping has been filled in already by a role with a higher priority,
 | 
						|
            // ignore the mapping.
 | 
						|
            Log::debug(sprintf('Column #%d ("%s") has something.', $column, $role));
 | 
						|
 | 
						|
 | 
						|
            return $role;
 | 
						|
        }
 | 
						|
        $roleMapping = [
 | 
						|
            'account-id'            => 'account-id',
 | 
						|
            'account-name'          => 'account-id',
 | 
						|
            'account-iban'          => 'account-id',
 | 
						|
            'account-number'        => 'account-id',
 | 
						|
            'bill-id'               => 'bill-id',
 | 
						|
            'bill-name'             => 'bill-id',
 | 
						|
            'budget-id'             => 'budget-id',
 | 
						|
            'budget-name'           => 'budget-id',
 | 
						|
            'currency-id'           => 'currency-id',
 | 
						|
            'currency-name'         => 'currency-id',
 | 
						|
            'currency-code'         => 'currency-id',
 | 
						|
            'currency-symbol'       => 'currency-id',
 | 
						|
            'category-id'           => 'category-id',
 | 
						|
            'category-name'         => 'category-id',
 | 
						|
            'foreign-currency-id'   => 'foreign-currency-id',
 | 
						|
            'foreign-currency-code' => 'foreign-currency-id',
 | 
						|
            'opposing-id'           => 'opposing-id',
 | 
						|
            'opposing-name'         => 'opposing-id',
 | 
						|
            'opposing-iban'         => 'opposing-id',
 | 
						|
            'opposing-number'       => 'opposing-id',
 | 
						|
        ];
 | 
						|
        if (!isset($roleMapping[$role])) {
 | 
						|
            throw new FireflyException(sprintf('Cannot indicate new role for mapped role "%s"', $role)); // @codeCoverageIgnore
 | 
						|
        }
 | 
						|
        $newRole = $roleMapping[$role];
 | 
						|
        Log::debug(sprintf('Role was "%s", but because of mapping (mapped to #%d), role becomes "%s"', $role, $mapped, $newRole));
 | 
						|
 | 
						|
        // also store the $mapped values in a "mappedValues" array.
 | 
						|
        $this->mappedValues[$newRole][] = $mapped;
 | 
						|
        Log::debug(sprintf('Values mapped to role "%s" are: ', $newRole), $this->mappedValues[$newRole]);
 | 
						|
 | 
						|
        return $newRole;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * @param array $line
 | 
						|
     *
 | 
						|
     * @return array
 | 
						|
     * @throws FireflyException
 | 
						|
     */
 | 
						|
    private function processLine(array $line): array
 | 
						|
    {
 | 
						|
        $return = [];
 | 
						|
        foreach ($line as $columnIndex => $value) {
 | 
						|
            $value        = trim($value);
 | 
						|
            $originalRole = $this->roles[$columnIndex] ?? '_ignore';
 | 
						|
            Log::debug(sprintf('Now at column #%d (%s), value "%s"', $columnIndex, $originalRole, $value));
 | 
						|
            if ('_ignore' !== $originalRole && '' != $value) {
 | 
						|
 | 
						|
                // is a mapped value present?
 | 
						|
                $mapped = $this->mapping[$columnIndex][$value] ?? 0;
 | 
						|
                // the role might change.
 | 
						|
                $role = $this->getRoleForColumn($columnIndex, $mapped);
 | 
						|
 | 
						|
                $columnValue = new ColumnValue;
 | 
						|
                $columnValue->setValue($value);
 | 
						|
                $columnValue->setRole($role);
 | 
						|
                $columnValue->setMappedValue($mapped);
 | 
						|
                $columnValue->setOriginalRole($originalRole);
 | 
						|
                $return[] = $columnValue;
 | 
						|
            }
 | 
						|
            if ('' === $value) {
 | 
						|
                Log::debug('Column skipped because value is empty.');
 | 
						|
            }
 | 
						|
        }
 | 
						|
        // add a special column value for the "source"
 | 
						|
        $columnValue = new ColumnValue;
 | 
						|
        $columnValue->setValue(sprintf('csv-import-v%s', config('firefly.version')));
 | 
						|
        $columnValue->setMappedValue(0);
 | 
						|
        $columnValue->setRole('original-source');
 | 
						|
        $return[] = $columnValue;
 | 
						|
 | 
						|
        return $return;
 | 
						|
    }
 | 
						|
 | 
						|
}
 |