Can configure file upload in file imports.

This commit is contained in:
James Cole 2018-05-06 07:09:08 +02:00
parent f74b9ba7ab
commit 7d80ac37a6
19 changed files with 791 additions and 205 deletions

View File

@ -29,6 +29,8 @@ use FireflyIII\Import\JobConfiguration\JobConfigurationInterface;
use FireflyIII\Models\ImportJob;
use FireflyIII\Repositories\ImportJob\ImportJobRepositoryInterface;
use Illuminate\Http\Request;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\MessageBag;
use Log;
/**
@ -139,8 +141,17 @@ class JobConfigurationController extends Controller
return redirect(route('import.job.status.index', [$importJob->key]));
}
// uploaded files are attached to the job.
// the configurator can then handle them.
$result = new MessageBag;
/** @var UploadedFile $upload */
foreach ($request->allFiles() as $name => $upload) {
$result = $this->repository->storeFileUpload($importJob, $name, $upload);
}
$data = $request->all();
$messages = $configurator->configureJob($data);
$result->merge($messages);
if ($messages->count() > 0) {
$request->session()->flash('warning', $messages->first());

View File

@ -23,11 +23,20 @@ declare(strict_types=1);
namespace FireflyIII\Import\JobConfiguration;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\ImportJob;
use FireflyIII\Repositories\ImportJob\ImportJobRepositoryInterface;
use FireflyIII\Support\Import\Configuration\File\ConfigurationInterface;
use FireflyIII\Support\Import\Configuration\File\ConfigureUploadHandler;
use FireflyIII\Support\Import\Configuration\File\NewFileJobHandler;
use Illuminate\Support\MessageBag;
class FileJobConfiguration implements JobConfigurationInterface
{
/** @var ImportJob */
private $importJob;
/** @var ImportJobRepositoryInterface */
private $repository;
/**
* ConfiguratorInterface constructor.
@ -43,30 +52,86 @@ class FileJobConfiguration implements JobConfigurationInterface
* @param array $data
*
* @return MessageBag
* @throws FireflyException
*/
public function configureJob(array $data): MessageBag
{
// TODO: Implement configureJob() method.
$configurator = $this->getConfigurationObject();
$configurator->setJob($this->importJob);
return $configurator->configureJob($data);
}
/**
* Return the data required for the next step in the job configuration.
*
* @throws FireflyException
* @return array
*/
public function getNextData(): array
{
// TODO: Implement getNextData() method.
$configurator = $this->getConfigurationObject();
$configurator->setJob($this->importJob);
return $configurator->getNextData();
}
/**
* Get the configuration handler for this specific stage.
*
* @return ConfigurationInterface
* @throws FireflyException
*/
private function getConfigurationObject(): ConfigurationInterface
{
$class = 'DoNotExist';
switch ($this->importJob->stage) {
case 'new': // has nothing, no file upload or anything.
$class = NewFileJobHandler::class;
break;
case 'configure-upload':
$class = ConfigureUploadHandler::class;
break;
// case 'upload-config': // has file, needs file config.
// $class = UploadConfig::class;
// break;
// case 'roles': // has configured file, needs roles.
// $class = Roles::class;
// break;
// case 'map': // has roles, needs mapping.
// $class = Map::class;
// break;
// default:
// break;
}
if (!class_exists($class)) {
throw new FireflyException(sprintf('Class %s does not exist in getConfigurationClass().', $class)); // @codeCoverageIgnore
}
return app($class);
}
/**
* Returns the view of the next step in the job configuration.
*
* @throws FireflyException
* @return string
*/
public function getNextView(): string
{
// TODO: Implement getNextView() method.
switch ($this->importJob->stage) {
case 'new':
return 'import.file.new';
case 'configure-upload':
return 'import.file.configure-upload';
break;
default:
// @codeCoverageIgnoreStart
throw new FireflyException(
sprintf('FileJobConfiguration::getNextView() cannot handle stage "%s"', $this->importJob->stage)
);
// @codeCoverageIgnoreEnd
}
}
/**
@ -76,7 +141,11 @@ class FileJobConfiguration implements JobConfigurationInterface
*/
public function configurationComplete(): bool
{
// TODO: Implement configurationComplete() method.
if ($this->importJob->stage === 'ready_to run') {
return true;
}
return false;
}
/**
@ -84,6 +153,8 @@ class FileJobConfiguration implements JobConfigurationInterface
*/
public function setJob(ImportJob $job): void
{
// TODO: Implement setJob() method.
$this->importJob = $job;
$this->repository = app(ImportJobRepositoryInterface::class);
$this->repository->setUser($job->user);
}
}

View File

@ -41,7 +41,7 @@ class AbnAmroDescription implements SpecificInterface
*/
public static function getDescription(): string
{
return 'Fixes possible problems with ABN Amro descriptions.';
return 'import.specific_abn_descr';
}
/**
@ -50,7 +50,7 @@ class AbnAmroDescription implements SpecificInterface
*/
public static function getName(): string
{
return 'ABN Amro description';
return 'import.specific_abn_name';
}
/**

View File

@ -43,7 +43,7 @@ class IngDescription implements SpecificInterface
*/
public static function getDescription(): string
{
return 'Create better descriptions in ING import files.';
return 'import.specific_ing_descr';
}
/**
@ -52,7 +52,7 @@ class IngDescription implements SpecificInterface
*/
public static function getName(): string
{
return 'ING description';
return 'import.specific_ing_name';
}
/**

View File

@ -33,7 +33,7 @@ class PresidentsChoice implements SpecificInterface
*/
public static function getDescription(): string
{
return 'Fixes problems with files from Presidents Choice Financial.';
return 'import.specific_pres_descr';
}
/**
@ -42,7 +42,7 @@ class PresidentsChoice implements SpecificInterface
*/
public static function getName(): string
{
return 'Presidents "Choice"';
return 'import.specific_pres_name';
}
/**

View File

@ -35,7 +35,7 @@ class RabobankDescription implements SpecificInterface
*/
public static function getDescription(): string
{
return 'Fixes possible problems with Rabobank descriptions.';
return 'import.specific_pres_descr';
}
/**
@ -44,7 +44,7 @@ class RabobankDescription implements SpecificInterface
*/
public static function getName(): string
{
return 'Rabobank description';
return 'import.specific_rabo_name';
}
/**

View File

@ -33,7 +33,7 @@ class SnsDescription implements SpecificInterface
*/
public static function getDescription(): string
{
return 'Trim quotes from SNS descriptions.';
return 'import.specific_sns_descr';
}
/**
@ -42,7 +42,7 @@ class SnsDescription implements SpecificInterface
*/
public static function getName(): string
{
return 'SNS description';
return 'import.specific_sns_name';
}
/**

View File

@ -52,6 +52,15 @@ class ImportJob extends Model
/** @var array */
protected $fillable = ['key', 'user_id', 'file_type', 'provider', 'status', 'stage', 'configuration', 'extended_status', 'transactions', 'errors'];
/**
* @codeCoverageIgnore
* @return \Illuminate\Database\Eloquent\Relations\MorphMany
*/
public function attachments()
{
return $this->morphMany(Attachment::class, 'attachable');
}
/**
* @param $value
*

View File

@ -24,11 +24,13 @@ namespace FireflyIII\Repositories\ImportJob;
use Crypt;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Attachment;
use FireflyIII\Models\ImportJob;
use FireflyIII\Models\Tag;
use FireflyIII\Models\TransactionJournalMeta;
use FireflyIII\Repositories\User\UserRepositoryInterface;
use FireflyIII\User;
use Illuminate\Support\MessageBag;
use Illuminate\Support\Str;
use Log;
use SplFileObject;
@ -42,6 +44,16 @@ class ImportJobRepository implements ImportJobRepositoryInterface
{
/** @var User */
private $user;
/** @var int */
private $maxUploadSize;
/** @var \Illuminate\Contracts\Filesystem\Filesystem */
protected $uploadDisk;
public function __construct()
{
$this->maxUploadSize = (int)config('firefly.maxUploadSize');
$this->uploadDisk = Storage::disk('upload');
}
/**
* @param ImportJob $job
@ -421,6 +433,8 @@ class ImportJobRepository implements ImportJobRepositoryInterface
/**
* Return import file content.
*
* @deprecated
*
* @param ImportJob $job
*
* @return string
@ -476,4 +490,74 @@ class ImportJobRepository implements ImportJobRepositoryInterface
return $job;
}
/**
* @codeCoverageIgnore
*
* @param UploadedFile $file
*
* @return bool
*/
protected function validSize(UploadedFile $file): bool
{
$size = $file->getSize();
return $size > $this->maxUploadSize;
}
/**
* Handle upload for job.
*
* @param ImportJob $job
* @param string $name
* @param UploadedFile $file
*
* @return MessageBag
* @throws FireflyException
*/
public function storeFileUpload(ImportJob $job, string $name, UploadedFile $file): MessageBag
{
$messages = new MessageBag;
if ($this->validSize($file)) {
$name = e($file->getClientOriginalName());
$messages->add('size', (string)trans('validation.file_too_large', ['name' => $name]));
return $messages;
}
$count = $job->attachments()->get()->filter(
function (Attachment $att) use($name) {
return $att->filename === $name;
}
)->count();
if ($count > 0) {
// don't upload, but also don't complain about it.
Log::error(sprintf('Detected duplicate upload. Will ignore second "%s" file.', $name));
return new MessageBag;
}
$attachment = new Attachment; // create Attachment object.
$attachment->user()->associate($job->user);
$attachment->attachable()->associate($job);
$attachment->md5 = md5_file($file->getRealPath());
$attachment->filename = $name;
$attachment->mime = $file->getMimeType();
$attachment->size = $file->getSize();
$attachment->uploaded = 0;
$attachment->save();
$fileObject = $file->openFile('r');
$fileObject->rewind();
$content = $fileObject->fread($file->getSize());
$encrypted = Crypt::encrypt($content);
// store it:
$this->uploadDisk->put($attachment->fileName(), $encrypted);
$attachment->uploaded = 1; // update attachment
$attachment->save();
// return it.
return new MessageBag;
}
}

View File

@ -22,9 +22,11 @@ declare(strict_types=1);
namespace FireflyIII\Repositories\ImportJob;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\ImportJob;
use FireflyIII\Models\Tag;
use FireflyIII\User;
use Illuminate\Support\MessageBag;
use Symfony\Component\HttpFoundation\File\UploadedFile;
/**
@ -33,6 +35,18 @@ use Symfony\Component\HttpFoundation\File\UploadedFile;
interface ImportJobRepositoryInterface
{
/**
* Handle upload for job.
*
* @param ImportJob $job
* @param string $name
* @param UploadedFile $file
*
* @return MessageBag
* @throws FireflyException
*/
public function storeFileUpload(ImportJob $job, string $name, UploadedFile $file): MessageBag;
/**
* @param ImportJob $job
* @param array $transactions

View File

@ -145,16 +145,6 @@ class ExpandedForm
*/
public function assetAccountList(string $name, $value = null, array $options = []): string
{
// properties for cache
$cache = new CacheProperties;
$cache->addProperty('exp-form-asset-list');
$cache->addProperty($name);
$cache->addProperty($value);
$cache->addProperty($options);
if ($cache->has()) {
return $cache->get();
}
// make repositories
/** @var AccountRepositoryInterface $repository */
$repository = app(AccountRepositoryInterface::class);
@ -182,7 +172,6 @@ class ExpandedForm
$grouped[$key][$account->id] = $account->name . ' (' . app('amount')->formatAnything($currency, $balance, false) . ')';
}
$res = $this->select($name, $grouped, $value, $options);
$cache->store($res);
return $res;
}

View File

@ -20,12 +20,12 @@
*/
declare(strict_types=1);
namespace FireflyIII\Support\Import\Configuration;
namespace FireflyIII\Support\Import\Configuration\File;
use FireflyIII\Models\ImportJob;
use Illuminate\Support\MessageBag;
/**
* @deprecated
* Class ConfigurationInterface.
*/
interface ConfigurationInterface
@ -35,14 +35,7 @@ interface ConfigurationInterface
*
* @return array
*/
public function getData(): array;
/**
* Return possible warning to user.
*
* @return string
*/
public function getWarningMessage(): string;
public function getNextData(): array;
/**
* @param ImportJob $job
@ -52,11 +45,11 @@ interface ConfigurationInterface
public function setJob(ImportJob $job);
/**
* Store the result.
* Store data associated with current stage.
*
* @param array $data
*
* @return bool
* @return MessageBag
*/
public function storeConfiguration(array $data): bool;
public function configureJob(array $data): MessageBag;
}

View File

@ -0,0 +1,167 @@
<?php
/**
* ConfigureUploadHandlerphp
* 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\Configuration\File;
use FireflyIII\Models\ImportJob;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\ImportJob\ImportJobRepositoryInterface;
use Illuminate\Support\MessageBag;
use Log;
/**
* Class ConfigureUploadHandler
*
* @package FireflyIII\Support\Import\Configuration\File
*/
class ConfigureUploadHandler implements ConfigurationInterface
{
/** @var ImportJob */
private $importJob;
/** @var ImportJobRepositoryInterface */
private $repository;
/** @var AccountRepositoryInterface */
private $accountRepos;
/**
* Get the data necessary to show the configuration screen.
*
* @return array
*/
public function getNextData(): array
{
$delimiters = [
',' => trans('form.csv_comma'),
';' => trans('form.csv_semicolon'),
'tab' => trans('form.csv_tab'),
];
$config = $this->importJob->configuration;
$config['date-format'] = $config['date-format'] ?? 'Ymd';
$specifics = [];
$this->repository->setConfiguration($this->importJob, $config);
// collect specifics.
foreach (config('csv.import_specifics') as $name => $className) {
$specifics[$name] = [
'name' => $className::getName(),
'description' => $className::getDescription(),
];
}
$data = [
'accounts' => [],
'specifix' => [],
'delimiters' => $delimiters,
'specifics' => $specifics,
];
return $data;
}
/**
* @param ImportJob $job
*
* @return ConfigurationInterface
*/
public function setJob(ImportJob $job)
{
$this->importJob = $job;
$this->repository = app(ImportJobRepositoryInterface::class);
$this->repository->setUser($job->user);
$this->accountRepos = app(AccountRepositoryInterface::class);
$this->accountRepos->setUser($job->user);
}
/**
* Store data associated with current stage.
*
* @param array $data
*
* @return MessageBag
*/
public function configureJob(array $data): MessageBag
{
$config = $this->importJob->configuration;
$complete = true;
// collect values:
$importId = isset($data['csv_import_account']) ? (int)$data['csv_import_account'] : 0;
$delimiter = (string)$data['csv_delimiter'];
$config['has-headers'] = (int)($data['has_headers'] ?? 0.0) === 1;
$config['date-format'] = (string)$data['date_format'];
$config['delimiter'] = 'tab' === $delimiter ? "\t" : $delimiter;
$config['apply-rules'] = (int)($data['apply_rules'] ?? 0.0) === 1;
$config['specifics'] = $this->getSpecifics($data);
// validate values:
$account = $this->accountRepos->findNull($importId);
// respond to invalid account:
if (null === $account) {
Log::error('Could not find anything for csv_import_account.', ['id' => $importId]);
$complete = false;
}
if (null !== $account) {
$config['import-account'] = $account->id;
}
$this->repository->setConfiguration($this->importJob, $config);
if ($complete) {
$this->repository->setStage($this->importJob, 'roles');
}
if (!$complete) {
$messages = new MessageBag;
$messages->add('account', trans('import.invalid_import_account'));
return $messages;
}
return new MessageBag;
}
/**
* @param array $data
*
* @return array
*/
private function getSpecifics(array $data): array
{
$return = [];
// check if specifics given are correct:
if (isset($data['specifics']) && \is_array($data['specifics'])) {
foreach ($data['specifics'] as $name) {
// verify their content.
$className = sprintf('FireflyIII\Import\Specifics\%s', $name);
if (class_exists($className)) {
$return[$name] = 1;
}
}
}
return $return;
}
}

View File

@ -0,0 +1,176 @@
<?php
/**
* NewFileJobHandler.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\Configuration\File;
use Crypt;
use FireflyIII\Console\Commands\Import;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Attachment;
use FireflyIII\Models\ImportJob;
use FireflyIII\Repositories\ImportJob\ImportJobRepositoryInterface;
use Illuminate\Contracts\Encryption\DecryptException;
use Illuminate\Contracts\Filesystem\FileNotFoundException;
use Illuminate\Support\MessageBag;
use Log;
use Storage;
use Exception;
/**
* Class NewFileJobHandler
*
* @package FireflyIII\Support\Import\Configuration\File
*/
class NewFileJobHandler implements ConfigurationInterface
{
/** @var ImportJob */
private $importJob;
/** @var ImportJobRepositoryInterface */
private $repository;
/**
* Get the data necessary to show the configuration screen.
*
* @return array
*/
public function getNextData(): array
{
$importFileTypes = [];
$defaultImportType = config('import.options.file.default_import_format');
foreach (config('import.options.file.import_formats') as $type) {
$importFileTypes[$type] = trans('import.import_file_type_' . $type);
}
return [
'default_type' => $defaultImportType,
'file_types' => $importFileTypes,
];
}
/**
* @param ImportJob $job
*/
public function setJob(ImportJob $job): void
{
$this->importJob = $job;
$this->repository = app(ImportJobRepositoryInterface::class);
$this->repository->setUser($job->user);
}
/**
* Store data associated with current stage.
*
* @param array $data
*
* @throws FireflyException
* @return MessageBag
*/
public function configureJob(array $data): MessageBag
{
// nothing to store, validate upload
// and push to next stage.
$messages = new MessageBag;
$attachments = $this->importJob->attachments;
/** @var Attachment $attachment */
foreach ($attachments as $attachment) {
// check if content is UTF8:
if (!$this->isUTF8($attachment)) {
$message = trans('import.file_not_utf8');
Log::error($message);
$messages->add('import_file', $message);
// delete attachment:
try {
$attachment->delete();
} catch (Exception $e) {
throw new FireflyException(sprintf('Could not delete attachment: %s', $e->getMessage()));
}
return $messages;
}
// if file is configuration file, store it into the job.
if ($attachment->filename === 'configuration_file') {
$this->storeConfig($attachment);
}
}
$this->repository->setStage($this->importJob, 'configure-upload');
return new MessageBag();
}
/**
* @param Attachment $attachment
*
* @return bool
* @throws FireflyException
*/
private function isUTF8(Attachment $attachment): bool
{
$disk = Storage::disk('upload');
try {
$content = $disk->get(sprintf('at-%d.data', $attachment->id));
$content = Crypt::decrypt($content);
} catch (FileNotFoundException|DecryptException $e) {
Log::error($e->getMessage());
throw new FireflyException($e->getMessage());
}
$result = mb_detect_encoding($content, 'UTF-8', true);
if ($result === false) {
return false;
}
if ($result !== 'ASCII' && $result !== 'UTF-8') {
return false;
}
return true;
}
/**
* @param Attachment $attachment
*
* @throws FireflyException
*/
private function storeConfig(Attachment $attachment): void
{
$disk = Storage::disk('upload');
try {
$content = $disk->get(sprintf('at-%d.data', $attachment->id));
$content = Crypt::decrypt($content);
} catch (FileNotFoundException $e) {
Log::error($e->getMessage());
throw new FireflyException($e->getMessage());
}
$json = json_decode($content, true);
if (null !== $json) {
$this->repository->setConfiguration($this->importJob, $json);
}
}
}

View File

@ -0,0 +1,20 @@
$(function () {
"use strict";
var importMultiSelect = {
disableIfEmpty: true,
selectAllText: selectAllText,
nonSelectedText: nonSelectedText,
nSelectedText: nSelectedText,
allSelectedText: allSelectedText,
includeSelectAllOption: true,
enableFiltering: true,
enableCaseInsensitiveFiltering: true,
filterPlaceholder: filterPlaceholder,
enableHTML: true,
};
// make account select a hip new bootstrap multi-select thing.
$('#inputSpecifics').multiselect(importMultiSelect);
});

View File

@ -80,6 +80,39 @@ return [
'job_config_fake_song_text' => 'Mention the song "Golden years" to continue with the fake import.',
'job_config_fake_album_title' => 'Enter album name',
'job_config_fake_album_text' => 'Some import routines require extra data halfway through the import. In the case of the fake import provider, you must answer some weird questions. Enter "Station to station" to continue.',
// job configuration form the file provider
'job_config_file_upload_title' => 'Import setup (1/4) - Upload your file',
'job_config_file_upload_text' => 'This routine will help you import files from your bank into Firefly III. ',
'job_config_file_upload_help' => 'Select your file. Please make sure the file is UTF-8 encoded.',
'job_config_file_upload_config_help' => 'If you have previously imported data into Firefly III, you may have a configuration file, which will pre-set configuration values for you. For some banks, other users have kindly provided their <a href="https://github.com/firefly-iii/import-configurations/wiki">configuration file</a>',
'job_config_file_upload_type_help' => 'Select the type of file you will upload',
'job_config_file_upload_submit' => 'Upload files',
'import_file_type_csv' => 'CSV (comma separated values)',
'file_not_utf8' => 'The file you have uploaded is not encoded as UTF-8 or ASCII. Firefly III cannot handle such files. Please use Notepad++ or Sublime to convert your file to UTF-8.',
'job_config_uc_title' => 'Import setup (2/4) - Basic file setup',
'job_config_uc_text' => 'To be able to import your file correctly, please validate the options below.',
'job_config_uc_header_help' => 'Check this box if the first row of your CSV file are the column titles.',
'job_config_uc_date_help' => 'Date time format in your file. Follow the format as <a href="https://secure.php.net/manual/en/datetime.createfromformat.php#refsect1-datetime.createfromformat-parameters">this page</a> indicates. The default value will parse dates that look like this: :dateExample.',
'job_config_uc_delimiter_help' => 'Choose the field delimiter that is used in your input file. If not sure, comma is the safest option.',
'job_config_uc_account_help' => 'If your file does NOT contain information about your asset account(s), use this dropdown to select to which account the transactions in the file belong to.',
'job_config_uc_apply_rules_title' => 'Apply rules',
'job_config_uc_apply_rules_text' => 'Applies your rules to every imported transaction. Note that this slows the import significantly.',
'job_config_uc_specifics_title' => 'Bank-specific options',
'job_config_uc_specifics_txt' => 'Some banks deliver badly formatted files. Firefly III can fix those automatically. If your bank delivers such files, open an issue on GitHub.',
'job_config_uc_submit' => 'Continue',
'invalid_import_account' => 'You have selected an invalid account to import into.',
// specifics:
'specific_ing_name' => 'ING NL',
'specific_ing_descr' => 'Create better descriptions in ING exports',
'specific_sns_name' => 'SNS / Volksbank NL',
'specific_sns_descr' => 'Trim quotes from SNS / Volksbank export files',
'specific_abn_name' => 'ABN AMRO NL',
'specific_abn_descr' => 'Fixes potential problems with ABN AMRO files',
'specific_rabo_name' => 'Rabobank NL',
'specific_rabo_descr' => 'Fixes potential problems with Rabobank files',
'specific_pres_name' => 'President\'s Choice Financial CA',
'specific_pres_descr' => 'Fixes potential problems with PC files',
// import status page:
'import_with_key' => 'Import with key \':key\'',

View File

@ -0,0 +1,115 @@
{% extends "./layout/default" %}
{% block breadcrumbs %}
{{ Breadcrumbs.render(Route.getCurrentRoute.getName, importJob) }}
{% endblock %}
{% block content %}
<div class="row">
<div class="col-lg-12">
<div class="box">
<div class="box-header with-border">
<h3 class="box-title">{{ trans('import.job_config_uc_title') }}</h3>
</div>
<div class="box-body">
<p>
{{ trans('import.job_config_uc_text') }}
</p>
</div>
</div>
</div>
</div>
<form class="form-horizontal" action="{{ route('import.job.configuration.post', importJob.key) }}" method="post" enctype="multipart/form-data">
<input type="hidden" name="_token" value="{{ csrf_token() }}"/>
<div class="row">
<div class="col-lg-12">
<div class="box">
<div class="box-header with-border">
<h3 class="box-title">{{ trans('import.job_config_input') }}</h3>
</div>
<div class="box-body">
<div class="row">
<div class="col-lg-6">
<h4>{{ 'mandatoryFields'|_ }}</h4>
{{ ExpandedForm.checkbox('has_headers',1,importJob.configuration['has-headers'],{helpText: trans('import.job_config_uc_header_help')}) }}
{{ ExpandedForm.text('date_format',importJob.configuration['date-format'],{helpText: trans('import.job_config_uc_date_help', {dateExample: phpdate('Ymd')}) }) }}
{{ ExpandedForm.select('csv_delimiter', data.delimiters, importJob.configuration['delimiter'], {helpText: trans('import.job_config_uc_delimiter_help') } ) }}
{{ ExpandedForm.assetAccountList('csv_import_account', importJob.configuration['import-account'], {helpText: trans('import.job_config_uc_account_help')}) }}
<h4>{{ 'optionalFields'|_ }}</h4>
<div class="form-group">
<label for="apply_rules_label" class="col-sm-4 control-label">
{{ trans('import.job_config_uc_apply_rules_title') }}
</label>
<div class="col-sm-8">
<div class="checkbox"><label>
{{ Form.checkbox('apply_rules', '1',
importJob.configuration['apply-rules'] == true, {'id': 'apply_rules_label'}) }}
{{ trans('import.job_config_uc_apply_rules_text') }}
</label>
</div>
</div>
</div>
<div class="form-group">
<label for="inputSpecifics" class="col-sm-4 control-label">{{ trans('import.job_config_uc_specifics_title') }}</label>
<div class="col-sm-8">
<p>
{{ trans('import.job_config_uc_specifics_txt') }}
</p>
<select id="inputSpecifics" name="specifics[]" multiple class="form-control">
{% for type, specific in data.specifics %}
<option value="{{ type }}" {% if importJob.configuration.specifics[type] == 1 %}selected{% endif %}>
{{ trans(specific.name) }}
&lt;small&gt;&lt;br&gt;{{ trans(specific.description) }}&lt;/small&gt;
</option>
{% endfor %}
</select>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-lg-12">
<div class="box">
<div class="box-body">
<button type="submit" class="pull-right btn btn-success">
{{ trans('import.job_config_uc_submit') }}
</button>
</div>
</div>
</div>
</div>
</form>
<p>
<br/>&nbsp;<br/>&nbsp;<br/>&nbsp;<br/>&nbsp;<br/>&nbsp;<br/>&nbsp;<br/>
</p>
{% endblock %}
{% block styles %}
<link href="css/bootstrap-multiselect.css?v={{ FF_VERSION }}" rel="stylesheet" type="text/css"/>
{% endblock %}
{% block scripts %}
<script type="text/javascript">
var selectAllText = "{{ trans('firefly.multi_select_select_all')|escape('js') }}";
var nonSelectedText = "{{ trans('firefly.multi_select_no_selection')|escape('js') }}";
var nSelectedText = "{{ trans('firefly.multi_select_n_selected')|escape('js') }}";
var allSelectedText = "{{ trans('firefly.multi_select_all_selected')|escape('js') }}";
var filterPlaceholder = "{{ trans('firefly.multi_select_filter_placeholder')|escape('js') }}";
</script>
<script type="text/javascript" src="js/lib/bootstrap-multiselect.js?v={{ FF_VERSION }}"></script>
<script type="text/javascript" src="js/ff/import/file/configure-upload.js?v={{ FF_VERSION }}"></script>
{% endblock %}

View File

@ -8,11 +8,11 @@
<div class="col-lg-12">
<div class="box">
<div class="box-header with-border">
<h3 class="box-title">{{ trans('import.file_upload_title') }}</h3>
<h3 class="box-title">{{ trans('import.job_config_file_upload_title') }}</h3>
</div>
<div class="box-body">
<p>
{{ trans('import.file_upload_text') }}
{{ trans('import.job_config_file_upload_text') }}
</p>
</div>
</div>
@ -28,12 +28,12 @@
<div class="col-lg-12">
<div class="box">
<div class="box-header with-border">
<h3 class="box-title">{{ trans('import.file_upload_fields') }}</h3>
<h3 class="box-title">{{ trans('import.job_config_input') }}</h3>
</div>
<div class="box-body">
{{ ExpandedForm.file('import_file', {helpText: trans('import.file_upload_help')}) }}
{{ ExpandedForm.file('configuration_file', {helpText: trans('import.file_upload_config_help')|raw}) }}
{{ ExpandedForm.select('import_file_type', data.file_types, data.default_type, {'helpText' : trans('import.file_upload_type_help')}) }}
{{ ExpandedForm.file('import_file', {helpText: trans('import.job_config_file_upload_help')}) }}
{{ ExpandedForm.file('configuration_file', {helpText: trans('import.job_config_file_upload_config_help')|raw}) }}
{{ ExpandedForm.select('import_file_type', data.file_types, data.default_type, {'helpText' : trans('import.job_config_file_upload_type_help')}) }}
</div>
</div>
</div>
@ -43,7 +43,7 @@
<div class="box">
<div class="box-body">
<button type="submit" class="btn btn-success pull-right">
{{ trans('import.file_upload_submit') }} <i class="fa fa-arrow-right"></i>
{{ trans('import.job_config_file_upload_submit') }} <i class="fa fa-arrow-right"></i>
</button>
</div>
</div>

View File

@ -1,96 +0,0 @@
{% extends "./layout/default" %}
{% block breadcrumbs %}
{{ Breadcrumbs.render(Route.getCurrentRoute.getName, job) }}
{% endblock %}
{% block content %}
<div class="row">
<div class="col-lg-12">
<div class="box">
<div class="box-header with-border">
<h3 class="box-title">{{ trans('import.csv_initial_title') }}</h3>
</div>
<div class="box-body">
<p>
{{ trans('import.csv_initial_text') }}
</p>
</div>
</div>
</div>
</div>
<form class="form-horizontal" action="{{ route('import.configure.post', job.key) }}" method="post" enctype="multipart/form-data">
<input type="hidden" name="_token" value="{{ csrf_token() }}"/>
<div class="row">
<div class="col-lg-12">
<div class="box">
<div class="box-header with-border">
<h3 class="box-title">{{ trans('import.csv_initial_box_title') }}</h3>
</div>
<div class="box-body">
<div class="row">
<div class="col-lg-6">
<h4>{{ 'mandatoryFields'|_ }}</h4>
{{ ExpandedForm.checkbox('has_headers',1,job.configuration['has-headers'],{helpText: trans('import.csv_initial_header_help')}) }}
{{ ExpandedForm.text('date_format',job.configuration['date-format'],{helpText: trans('import.csv_initial_date_help', {dateExample: phpdate('Ymd')}) }) }}
{{ ExpandedForm.select('csv_delimiter', data.delimiters, job.configuration['delimiter'], {helpText: trans('import.csv_initial_delimiter_help') } ) }}
{{ ExpandedForm.select('csv_import_account', data.accounts, job.configuration['import-account'], {helpText: trans('import.csv_initial_import_account_help')} ) }}
<h4>{{ 'optionalFields'|_ }}</h4>
<div class="form-group">
<label for="apply_rules_label" class="col-sm-4 control-label">
{{ trans('import.file_apply_rules_title') }}
</label>
<div class="col-sm-8">
<div class="checkbox"><label>
{{ Form.checkbox('apply_rules', '1',
job.configuration['apply-rules'] == true, {'id': 'apply_rules_label'}) }}
{{ trans('import.file_apply_rules_description') }}
</label>
</div>
</div>
</div>
{% for type, specific in data.specifics %}
<div class="form-group">
<label for="{{ type }}_label" class="col-sm-4 control-label">
{{ specific.name }}
</label>
<div class="col-sm-8">
<div class="checkbox"><label>
{{ Form.checkbox('specifics['~type~']', '1',
job.configuration.specifics[type] == '1', {'id': type ~ '_label'}) }}
{{ specific.description }}
</label>
</div>
</div>
</div>
{% endfor %}
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-lg-12">
<div class="box">
<div class="box-body">
<button type="submit" class="pull-right btn btn-success">
{{ trans('import.csv_initial_submit') }}
</button>
</div>
</div>
</div>
</div>
</form>
{% endblock %}