mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-07-09 03:14:30 -04:00
Working on import
This commit is contained in:
parent
24bcb0e2e5
commit
5c6b2fe906
@ -37,7 +37,6 @@ use App\Models\Timezone;
|
|||||||
use App\Models\Industry;
|
use App\Models\Industry;
|
||||||
use App\Models\InvoiceDesign;
|
use App\Models\InvoiceDesign;
|
||||||
use App\Models\TaxRate;
|
use App\Models\TaxRate;
|
||||||
use App\Ninja\Import\DataImporterServiceInterface;
|
|
||||||
use App\Ninja\Repositories\AccountRepository;
|
use App\Ninja\Repositories\AccountRepository;
|
||||||
use App\Ninja\Repositories\ClientRepository;
|
use App\Ninja\Repositories\ClientRepository;
|
||||||
use App\Ninja\Repositories\ReferralRepository;
|
use App\Ninja\Repositories\ReferralRepository;
|
||||||
@ -57,7 +56,7 @@ class AccountController extends BaseController
|
|||||||
protected $contactMailer;
|
protected $contactMailer;
|
||||||
protected $referralRepository;
|
protected $referralRepository;
|
||||||
|
|
||||||
public function __construct(AccountRepository $accountRepo, UserMailer $userMailer, ContactMailer $contactMailer, ReferralRepository $referralRepository, ClientRepository $clientRepository, DataImporterServiceInterface $dataImporterService)
|
public function __construct(AccountRepository $accountRepo, UserMailer $userMailer, ContactMailer $contactMailer, ReferralRepository $referralRepository, ClientRepository $clientRepository)
|
||||||
{
|
{
|
||||||
parent::__construct();
|
parent::__construct();
|
||||||
|
|
||||||
@ -66,7 +65,6 @@ class AccountController extends BaseController
|
|||||||
$this->contactMailer = $contactMailer;
|
$this->contactMailer = $contactMailer;
|
||||||
$this->referralRepository = $referralRepository;
|
$this->referralRepository = $referralRepository;
|
||||||
$this->clientRepository = $clientRepository;
|
$this->clientRepository = $clientRepository;
|
||||||
$this->dataImporterService = $dataImporterService;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function demo()
|
public function demo()
|
||||||
@ -417,8 +415,6 @@ class AccountController extends BaseController
|
|||||||
return AccountController::saveLocalization();
|
return AccountController::saveLocalization();
|
||||||
} elseif ($section === ACCOUNT_IMPORT_EXPORT) {
|
} elseif ($section === ACCOUNT_IMPORT_EXPORT) {
|
||||||
return AccountController::importFile();
|
return AccountController::importFile();
|
||||||
} elseif ($section === IMPORT_FROM_FRESHBOOKS) {
|
|
||||||
return AccountController::importData();
|
|
||||||
} elseif ($section === ACCOUNT_MAP) {
|
} elseif ($section === ACCOUNT_MAP) {
|
||||||
return AccountController::mapFile();
|
return AccountController::mapFile();
|
||||||
} elseif ($section === ACCOUNT_NOTIFICATIONS) {
|
} elseif ($section === ACCOUNT_NOTIFICATIONS) {
|
||||||
@ -737,26 +733,6 @@ class AccountController extends BaseController
|
|||||||
return Redirect::to('clients');
|
return Redirect::to('clients');
|
||||||
}
|
}
|
||||||
|
|
||||||
private function importData()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
$files['client'] = Input::file('client_file');
|
|
||||||
$files['invoice'] = Input::file('invoice_file');
|
|
||||||
$files['timesheet'] = Input::file('timesheet_file');
|
|
||||||
$imported_files = $this->dataImporterService->import($files);
|
|
||||||
}
|
|
||||||
catch(Exception $e)
|
|
||||||
{
|
|
||||||
Session::flash('error', $e->getMessage());
|
|
||||||
return Redirect::to('settings/' . ACCOUNT_IMPORT_EXPORT);
|
|
||||||
}
|
|
||||||
|
|
||||||
Session::flash('message', trans('texts.imported_file').' - '.$imported_files);
|
|
||||||
|
|
||||||
return Redirect::to('settings/' . ACCOUNT_IMPORT_EXPORT);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function mapFile()
|
private function mapFile()
|
||||||
{
|
{
|
||||||
$file = Input::file('file');
|
$file = Input::file('file');
|
||||||
|
@ -14,7 +14,7 @@ use App\Models\Task;
|
|||||||
use App\Models\Invoice;
|
use App\Models\Invoice;
|
||||||
use App\Models\Payment;
|
use App\Models\Payment;
|
||||||
|
|
||||||
class ImportExportController extends BaseController
|
class ExportController extends BaseController
|
||||||
{
|
{
|
||||||
public function doExport(Request $request)
|
public function doExport(Request $request)
|
||||||
{
|
{
|
38
app/Http/Controllers/ImportController.php
Normal file
38
app/Http/Controllers/ImportController.php
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
<?php namespace app\Http\Controllers;
|
||||||
|
|
||||||
|
use Input;
|
||||||
|
use Session;
|
||||||
|
use Redirect;
|
||||||
|
use App\Services\ImportService;
|
||||||
|
use App\Http\Controllers\BaseController;
|
||||||
|
|
||||||
|
class ImportController extends BaseController
|
||||||
|
{
|
||||||
|
public function __construct(ImportService $importService)
|
||||||
|
{
|
||||||
|
parent::__construct();
|
||||||
|
|
||||||
|
$this->importService = $importService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function doImport()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$files = [];
|
||||||
|
foreach (ImportService::$entityTypes as $entityType) {
|
||||||
|
if (Input::file("{$entityType}_file")) {
|
||||||
|
$files[$entityType] = Input::file("{$entityType}_file")->getRealPath();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$imported_files = $this->importService->import(Input::get('source'), $files);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
Session::flash('error', $e->getMessage());
|
||||||
|
|
||||||
|
return Redirect::to('/settings/'.ACCOUNT_IMPORT_EXPORT);
|
||||||
|
}
|
||||||
|
|
||||||
|
Session::flash('message', trans('texts.imported_file').' - '.$imported_files);
|
||||||
|
|
||||||
|
return Redirect::to('/settings/'.ACCOUNT_IMPORT_EXPORT);
|
||||||
|
}
|
||||||
|
}
|
@ -131,7 +131,9 @@ Route::group(['middleware' => 'auth'], function() {
|
|||||||
Route::post('user/setTheme', 'UserController@setTheme');
|
Route::post('user/setTheme', 'UserController@setTheme');
|
||||||
Route::post('remove_logo', 'AccountController@removeLogo');
|
Route::post('remove_logo', 'AccountController@removeLogo');
|
||||||
Route::post('account/go_pro', 'AccountController@enableProPlan');
|
Route::post('account/go_pro', 'AccountController@enableProPlan');
|
||||||
Route::post('/export', 'ImportExportController@doExport');
|
|
||||||
|
Route::post('/export', 'ExportController@doExport');
|
||||||
|
Route::post('/import', 'ImportController@doImport');
|
||||||
|
|
||||||
Route::resource('gateways', 'AccountGatewayController');
|
Route::resource('gateways', 'AccountGatewayController');
|
||||||
Route::get('api/gateways', array('as'=>'api.gateways', 'uses'=>'AccountGatewayController@getDatatable'));
|
Route::get('api/gateways', array('as'=>'api.gateways', 'uses'=>'AccountGatewayController@getDatatable'));
|
||||||
@ -337,7 +339,15 @@ if (!defined('CONTACT_EMAIL')) {
|
|||||||
define('DEFAULT_FONT_SIZE', 9);
|
define('DEFAULT_FONT_SIZE', 9);
|
||||||
define('DEFAULT_SEND_RECURRING_HOUR', 8);
|
define('DEFAULT_SEND_RECURRING_HOUR', 8);
|
||||||
|
|
||||||
define('IMPORT_FROM_FRESHBOOKS', 'import_from_freshbook');
|
define('IMPORT_CSV', 'CSV');
|
||||||
|
define('IMPORT_FRESHBOOKS', 'FreshBooks');
|
||||||
|
define('IMPORT_WAVE', 'Wave');
|
||||||
|
define('IMPORT_RONIN', 'Ronin');
|
||||||
|
define('IMPORT_HIVEAGE', 'Hiveage');
|
||||||
|
define('IMPORT_ZOHO', 'Zoho');
|
||||||
|
define('IMPORT_NUTCACHE', 'Nutcache');
|
||||||
|
define('IMPORT_INVOICEABLE', 'Invoiceable');
|
||||||
|
define('IMPORT_HARVEST', 'Harvest');
|
||||||
|
|
||||||
define('MAX_NUM_CLIENTS', 100);
|
define('MAX_NUM_CLIENTS', 100);
|
||||||
define('MAX_NUM_CLIENTS_PRO', 20000);
|
define('MAX_NUM_CLIENTS_PRO', 20000);
|
||||||
@ -432,7 +442,7 @@ if (!defined('CONTACT_EMAIL')) {
|
|||||||
define('PDFMAKE_DOCS', 'http://pdfmake.org/playground.html');
|
define('PDFMAKE_DOCS', 'http://pdfmake.org/playground.html');
|
||||||
define('PHANTOMJS_CLOUD', 'http://api.phantomjscloud.com/single/browser/v1/');
|
define('PHANTOMJS_CLOUD', 'http://api.phantomjscloud.com/single/browser/v1/');
|
||||||
define('PHP_DATE_FORMATS', 'http://php.net/manual/en/function.date.php');
|
define('PHP_DATE_FORMATS', 'http://php.net/manual/en/function.date.php');
|
||||||
define('REFERRAL_PROGRAM_URL', 'https://www.invoiceninja.com/affiliates/');
|
define('REFERRAL_PROGRAM_URL', 'https://www.invoiceninja.com/referral-program/');
|
||||||
|
|
||||||
define('COUNT_FREE_DESIGNS', 4);
|
define('COUNT_FREE_DESIGNS', 4);
|
||||||
define('COUNT_FREE_DESIGNS_SELF_HOST', 5); // include the custom design
|
define('COUNT_FREE_DESIGNS_SELF_HOST', 5); // include the custom design
|
||||||
|
@ -23,7 +23,7 @@ class InvoiceListener
|
|||||||
public function updatedInvoice(InvoiceWasUpdated $event)
|
public function updatedInvoice(InvoiceWasUpdated $event)
|
||||||
{
|
{
|
||||||
$invoice = $event->invoice;
|
$invoice = $event->invoice;
|
||||||
$invoice->updatePaidStatus();
|
$invoice->updatePaidStatus(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function viewedInvoice(InvoiceInvitationWasViewed $event)
|
public function viewedInvoice(InvoiceInvitationWasViewed $event)
|
||||||
|
@ -192,16 +192,20 @@ class Invoice extends EntityModel implements BalanceAffecting
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function updatePaidStatus()
|
public function updatePaidStatus($save = true)
|
||||||
{
|
{
|
||||||
if ($this->isPaid() && $this->balance > 0) {
|
if ($this->isPaid() && $this->balance > 0) {
|
||||||
$this->invoice_status_id = ($this->balance == $this->amount ? INVOICE_STATUS_SENT : INVOICE_STATUS_PARTIAL);
|
$this->invoice_status_id = ($this->balance == $this->amount ? INVOICE_STATUS_SENT : INVOICE_STATUS_PARTIAL);
|
||||||
|
if ($save) {
|
||||||
$this->save();
|
$this->save();
|
||||||
|
}
|
||||||
} elseif ($this->invoice_status_id && $this->amount > 0 && $this->balance == 0 && $this->invoice_status_id != INVOICE_STATUS_PAID) {
|
} elseif ($this->invoice_status_id && $this->amount > 0 && $this->balance == 0 && $this->invoice_status_id != INVOICE_STATUS_PAID) {
|
||||||
$this->invoice_status_id = INVOICE_STATUS_PAID;
|
$this->invoice_status_id = INVOICE_STATUS_PAID;
|
||||||
|
if ($save) {
|
||||||
$this->save();
|
$this->save();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function updateBalances($balanceAdjustment, $partial = 0)
|
public function updateBalances($balanceAdjustment, $partial = 0)
|
||||||
{
|
{
|
||||||
|
@ -1,15 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* Created by PhpStorm.
|
|
||||||
* User: eduardocruz
|
|
||||||
* Date: 11/9/15
|
|
||||||
* Time: 11:03
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace App\Ninja\Import;
|
|
||||||
|
|
||||||
|
|
||||||
interface DataImporterServiceInterface
|
|
||||||
{
|
|
||||||
public function import($files);
|
|
||||||
}
|
|
@ -1,107 +1,41 @@
|
|||||||
<?php
|
<?php namespace App\Ninja\Import\FreshBooks;
|
||||||
/**
|
|
||||||
* Created by PhpStorm.
|
|
||||||
* User: eduardocruz
|
|
||||||
* Date: 11/9/15
|
|
||||||
* Time: 11:47
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace app\Ninja\Import\FreshBooks;
|
|
||||||
|
|
||||||
use League\Fractal\TransformerAbstract;
|
use League\Fractal\TransformerAbstract;
|
||||||
use League\Fractal\Resource\Collection;
|
|
||||||
use stdClass;
|
|
||||||
use App\Models\Country;
|
use App\Models\Country;
|
||||||
|
use League\Fractal\Resource\Item;
|
||||||
|
|
||||||
class ClientTransformer extends TransformerAbstract
|
class ClientTransformer extends TransformerAbstract
|
||||||
{
|
{
|
||||||
|
public function transform($data, $maps)
|
||||||
|
|
||||||
|
|
||||||
public function transform($data)
|
|
||||||
{
|
{
|
||||||
return new Collection($data, function(array $data) {
|
if (isset($maps[ENTITY_CLIENT][$data->organization])) {
|
||||||
$data = $this->arrayToObject($data);
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($maps['countries'][$data->country])) {
|
||||||
|
$data->country_id = $maps['countries'][$data->country];
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Item($data, function ($data) use ($maps) {
|
||||||
return [
|
return [
|
||||||
'name' => $data->organization !== array() ? $data->organization : '',
|
'name' => $data->organization,
|
||||||
'work_phone' => $data->busPhone !== array() ? $data->busPhone : '',
|
'work_phone' => $data->busphone,
|
||||||
'address1' => $data->street !== array() ? $data->street : '',
|
'address1' => $data->street,
|
||||||
'address2' => $data->street2 !== array() ? $data->street2 : '',
|
'address2' => $data->street2,
|
||||||
'city' => $data->city !== array() ? $data->city : '',
|
'city' => $data->city,
|
||||||
'state' => $data->province !== array() ? $data->province : '',
|
'state' => $data->province,
|
||||||
'postal_code' => $data->postalCode !== array() ? $data->postalCode : '',
|
'postal_code' => $data->postalcode,
|
||||||
'private_notes' => $data->notes !== array() ? $data->notes : '',
|
'private_notes' => $data->notes,
|
||||||
'contacts' => [
|
'contacts' => [
|
||||||
[
|
[
|
||||||
'public_id' => '',
|
'first_name' => $data->firstname,
|
||||||
'first_name' => $data->firstName !== array() ? $data->firstName : '',
|
'last_name' => $data->lastname,
|
||||||
'last_name' => $data->lastName !== array() ? $data->lastName : '',
|
'email' => $data->email,
|
||||||
'email' => $data->email !== array() ? $data->email : '',
|
'phone' => $data->mobphone ?: $data->homephone,
|
||||||
'phone' => $data->mobPhone !== array() ? $data->mobPhone : $data->homePhone,
|
|
||||||
]
|
|
||||||
],
|
],
|
||||||
'country_id' => !Country::where('name', $data->country)
|
],
|
||||||
->get()
|
'country_id' => $data->country_id,
|
||||||
->isEmpty() ? Country::where('name', $data->country)
|
|
||||||
->first()->id : null,
|
|
||||||
];
|
];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private function arrayToObject($array)
|
|
||||||
{
|
|
||||||
$object = new stdClass();
|
|
||||||
$object->organization = $array[0];
|
|
||||||
$object->firstName = $array[1];
|
|
||||||
$object->lastName = $array[2];
|
|
||||||
$object->email = $array[3];
|
|
||||||
$object->street = $array[4];
|
|
||||||
$object->street2 = $array[5];
|
|
||||||
$object->city = $array[6];
|
|
||||||
$object->province = $array[7];
|
|
||||||
$object->country = $array[8];
|
|
||||||
$object->postalCode = $array[9];
|
|
||||||
$object->busPhone = $array[10];
|
|
||||||
$object->homePhone = $array[11];
|
|
||||||
$object->mobPhone = $array[12];
|
|
||||||
$object->fax = $array[13];
|
|
||||||
$object->secStreet = $array[14];
|
|
||||||
$object->secStreet2 = $array[15];
|
|
||||||
$object->secCity = $array[16];
|
|
||||||
$object->secProvince = $array[17];
|
|
||||||
$object->secCountry = $array[18];
|
|
||||||
$object->secPostalCode = $array[19];
|
|
||||||
$object->notes = $array[20];
|
|
||||||
return $object;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function validateHeader($csvHeader)
|
|
||||||
{
|
|
||||||
$header = [0 => "Organization",
|
|
||||||
1 => "FirstName",
|
|
||||||
2 => "LastName",
|
|
||||||
3 => "Email",
|
|
||||||
4 => "Street",
|
|
||||||
5 => "Street2",
|
|
||||||
6 => "City",
|
|
||||||
7 => "Province",
|
|
||||||
8 => "Country",
|
|
||||||
9 => "PostalCode",
|
|
||||||
10 => "BusPhone",
|
|
||||||
11 => "HomePhone",
|
|
||||||
12 => "MobPhone",
|
|
||||||
13 => "Fax",
|
|
||||||
14 => "SecStreet",
|
|
||||||
15 => "SecStreet2",
|
|
||||||
16 => "SecCity",
|
|
||||||
17 => "SecProvince",
|
|
||||||
18 => "SecCountry",
|
|
||||||
19 => "SecPostalCode",
|
|
||||||
20 => "Notes"];
|
|
||||||
|
|
||||||
if(!empty(array_diff($header, $csvHeader)))
|
|
||||||
throw new Exception(trans('texts.invalid_csv_header'));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
@ -1,154 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* Created by PhpStorm.
|
|
||||||
* User: eduardocruz
|
|
||||||
* Date: 11/9/15
|
|
||||||
* Time: 11:10
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace App\Ninja\Import\FreshBooks;
|
|
||||||
|
|
||||||
use Exception;
|
|
||||||
use App\Ninja\Import\DataImporterServiceInterface;
|
|
||||||
use League\Fractal\Manager;
|
|
||||||
use parseCSV;
|
|
||||||
use App\Ninja\Repositories\ClientRepository;
|
|
||||||
use App\Ninja\Repositories\InvoiceRepository;
|
|
||||||
use Illuminate\Contracts\Container\Container;
|
|
||||||
|
|
||||||
class FreshBooksDataImporterService implements DataImporterServiceInterface
|
|
||||||
{
|
|
||||||
|
|
||||||
protected $transformer;
|
|
||||||
//protected $repository;
|
|
||||||
protected $invoiceRepo;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* FreshBooksDataImporterService constructor.
|
|
||||||
*/
|
|
||||||
public function __construct(Manager $manager, ClientRepository $clientRepo, InvoiceRepository $invoiceRepo, Container $container)
|
|
||||||
{
|
|
||||||
$this->clientRepo = $clientRepo;
|
|
||||||
$this->invoiceRepo = $invoiceRepo;
|
|
||||||
$this->container = $container;
|
|
||||||
|
|
||||||
$this->fractal = $manager;
|
|
||||||
$this->transformerList = array(
|
|
||||||
'client' => __NAMESPACE__ . '\ClientTransformer',
|
|
||||||
'invoice' => __NAMESPACE__ . '\InvoiceTransformer',
|
|
||||||
'timesheet' => __NAMESPACE__ . '\TimesheetTransformer',
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->repositoryList = array(
|
|
||||||
'client' => '\App\Ninja\Repositories\ClientRepository',
|
|
||||||
'invoice' => '\App\Ninja\Repositories\InvoiceRepository',
|
|
||||||
'timesheet' => '\App\Ninja\Repositories\TaskRepository',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function import($files)
|
|
||||||
{
|
|
||||||
$imported_files = null;
|
|
||||||
|
|
||||||
foreach($files as $entity => $file)
|
|
||||||
{
|
|
||||||
$imported_files = $imported_files . $this->execute($entity, $file);
|
|
||||||
}
|
|
||||||
return $imported_files;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function execute($entity, $file)
|
|
||||||
{
|
|
||||||
$this->transformer = $this->createTransformer($entity);
|
|
||||||
$this->repository = $this->createRepository($entity);
|
|
||||||
|
|
||||||
$data = $this->parseCSV($file);
|
|
||||||
$ignore_header = true;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
$rows = $this->mapCsvToModel($data, $ignore_header);
|
|
||||||
} catch(Exception $e)
|
|
||||||
{
|
|
||||||
throw new Exception($e->getMessage() . ' - ' . $file->getClientOriginalName() );
|
|
||||||
}
|
|
||||||
|
|
||||||
$errorMessages = null;
|
|
||||||
|
|
||||||
foreach($rows as $row)
|
|
||||||
{
|
|
||||||
if($entity=='timesheet')
|
|
||||||
{
|
|
||||||
$publicId = false;
|
|
||||||
$this->repository->save($publicId, $row);
|
|
||||||
} else {
|
|
||||||
$this->repository->save($row);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
return $file->getClientOriginalName().' '.$errorMessages;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function parseCSV($file)
|
|
||||||
{
|
|
||||||
if ($file == null)
|
|
||||||
throw new Exception(trans('texts.select_file'));
|
|
||||||
|
|
||||||
$name = $file->getRealPath();
|
|
||||||
|
|
||||||
require_once app_path().'/Includes/parsecsv.lib.php';
|
|
||||||
$csv = new parseCSV();
|
|
||||||
$csv->heading = false;
|
|
||||||
$csv->auto($name);
|
|
||||||
|
|
||||||
//Review this code later. Free users can only have 100 clients.
|
|
||||||
/*
|
|
||||||
if (count($csv->data) + Client::scope()->count() > Auth::user()->getMaxNumClients()) {
|
|
||||||
$message = trans('texts.limit_clients', ['count' => Auth::user()->getMaxNumClients()]);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
return $csv->data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param $data
|
|
||||||
* Header of the Freshbook CSV File
|
|
||||||
|
|
||||||
* @param $ignore_header
|
|
||||||
* @return mixed
|
|
||||||
*/
|
|
||||||
private function mapCsvToModel($data, $ignore_header)
|
|
||||||
{
|
|
||||||
if($ignore_header)
|
|
||||||
{
|
|
||||||
$header = array_shift($data);
|
|
||||||
$this->transformer->validateHeader($header);
|
|
||||||
}
|
|
||||||
|
|
||||||
$resource = $this->transformer->transform($data);
|
|
||||||
$data = $this->fractal->createData($resource)->toArray();
|
|
||||||
|
|
||||||
return $data['data'];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function createTransformer($type)
|
|
||||||
{
|
|
||||||
if (!array_key_exists($type, $this->transformerList)) {
|
|
||||||
throw new \InvalidArgumentException("$type is not a valid Transformer");
|
|
||||||
}
|
|
||||||
$className = $this->transformerList[$type];
|
|
||||||
return new $className();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function createRepository($type)
|
|
||||||
{
|
|
||||||
if (!array_key_exists($type, $this->repositoryList)) {
|
|
||||||
throw new \InvalidArgumentException("$type is not a valid Repository");
|
|
||||||
}
|
|
||||||
$className = $this->repositoryList[$type];
|
|
||||||
return $this->container->make($className);
|
|
||||||
//return new $className();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,103 +1,40 @@
|
|||||||
<?php
|
<?php namespace App\Ninja\Import\FreshBooks;
|
||||||
/**
|
|
||||||
* Created by PhpStorm.
|
|
||||||
* User: eduardocruz
|
|
||||||
* Date: 11/9/15
|
|
||||||
* Time: 11:47
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace app\Ninja\Import\FreshBooks;
|
|
||||||
|
|
||||||
use App\Models\Client;
|
|
||||||
use Exception;
|
|
||||||
use League\Fractal\Resource\Collection;
|
|
||||||
use League\Fractal\TransformerAbstract;
|
use League\Fractal\TransformerAbstract;
|
||||||
use stdClass;
|
use League\Fractal\Resource\Item;
|
||||||
|
use App\Models\Client;
|
||||||
|
|
||||||
class InvoiceTransformer extends TransformerAbstract
|
class InvoiceTransformer extends TransformerAbstract
|
||||||
{
|
{
|
||||||
|
public function transform($data, $maps)
|
||||||
|
|
||||||
|
|
||||||
public function transform($data)
|
|
||||||
{
|
{
|
||||||
return new Collection($data, function(array $data) {
|
if (isset($maps[ENTITY_INVOICE][$data->invoice_number])) {
|
||||||
$data = $this->arrayToObject($data);
|
return false;
|
||||||
$client = Client::where('name', $data->organization)->orderBy('created_at', 'desc')->first();
|
}
|
||||||
$data->client_id = $client->id;
|
|
||||||
$data->user_id = $client->user_id;
|
if (isset($maps[ENTITY_CLIENT][$data->organization])) {
|
||||||
$data->account_id = $client->account_id;
|
$data->client_id = $maps[ENTITY_CLIENT][$data->organization];
|
||||||
$create_date = new \DateTime($data->create_date);
|
} else {
|
||||||
$data->create_date = date_format($create_date, DEFAULT_DATE_FORMAT);
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Item($data, function ($data) use ($maps) {
|
||||||
return [
|
return [
|
||||||
'invoice_number' => $data->invoice_number !== array() ? $data->invoice_number : '',
|
'invoice_number' => $data->invoice_number,
|
||||||
'client_id' => (int)$data->client_id !== array() ? $data->client_id : '',
|
'paid' => (float) $data->paid,
|
||||||
'user_id' => (int)$data->user_id !== array() ? $data->user_id : '',
|
'client_id' => (int) $data->client_id,
|
||||||
'account_id' => (int)$data->account_id !== array() ? $data->account_id : '',
|
'po_number' => $data->po_number,
|
||||||
'amount' => (int)$data->amount !== array() ? $data->amount : '',
|
'terms' => $data->terms,
|
||||||
'po_number' => $data->po_number !== array() ? $data->po_number : '',
|
'public_notes' => $data->notes,
|
||||||
'terms' => $data->terms !== array() ? $data->terms : '',
|
'invoice_date_sql' => $data->create_date,
|
||||||
'public_notes' => $data->notes !== array() ? $data->notes : '',
|
|
||||||
//Best guess on required fields
|
|
||||||
'invoice_date' => $data->create_date !== array() ? $data->create_date : '',
|
|
||||||
'due_date' => $data->create_date !== array() ? $data->create_date : '',
|
|
||||||
'discount' => 0,
|
|
||||||
'invoice_footer' => '',
|
|
||||||
'invoice_design_id' => 1,
|
|
||||||
'invoice_items' => '',
|
|
||||||
'is_amount_discount' => 0,
|
|
||||||
'partial' => 0,
|
|
||||||
'invoice_items' => [
|
'invoice_items' => [
|
||||||
[
|
[
|
||||||
'product_key' => '',
|
'notes' => $data->notes,
|
||||||
'notes' => $data->notes !== array() ? $data->notes : '',
|
'cost' => (float) $data->amount,
|
||||||
'task_public_id' => '',
|
|
||||||
'cost' => (int)$data->amount !== array() ? $data->amount : '',
|
|
||||||
'qty' => 1,
|
'qty' => 1,
|
||||||
'tax' => '',
|
|
||||||
'tax_name' => '',
|
|
||||||
'tax_rate' => 0
|
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
|
|
||||||
];
|
];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private function arrayToObject($array)
|
|
||||||
{
|
|
||||||
$object = new stdClass();
|
|
||||||
$object->invoice_number = $array[0];
|
|
||||||
$object->organization = $array[1];
|
|
||||||
$object->fname = $array[2];
|
|
||||||
$object->lname = $array[3];
|
|
||||||
$object->amount = $array[4];
|
|
||||||
$object->paid = $array[5];
|
|
||||||
$object->po_number = $array[6];
|
|
||||||
$object->create_date = $array[7];
|
|
||||||
$object->date_paid = $array[8];
|
|
||||||
$object->terms = $array[9];
|
|
||||||
$object->notes = $array[10];
|
|
||||||
return $object;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function validateHeader($csvHeader)
|
|
||||||
{
|
|
||||||
$header = [0 => "invoice_number",
|
|
||||||
1 => "organization",
|
|
||||||
2 => "fname",
|
|
||||||
3 => "lname",
|
|
||||||
4 => "amount",
|
|
||||||
5 => "paid",
|
|
||||||
6 => "po_number",
|
|
||||||
7 => "create_date",
|
|
||||||
8 => "date_paid",
|
|
||||||
9 => "terms",
|
|
||||||
10 => "notes"];
|
|
||||||
|
|
||||||
if(!empty(array_diff($header, $csvHeader)))
|
|
||||||
throw new Exception(trans('texts.invalid_csv_header'));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
19
app/Ninja/Import/FreshBooks/PaymentTransformer.php
Normal file
19
app/Ninja/Import/FreshBooks/PaymentTransformer.php
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<?php namespace App\Ninja\Import\FreshBooks;
|
||||||
|
|
||||||
|
use League\Fractal\TransformerAbstract;
|
||||||
|
use League\Fractal\Resource\Item;
|
||||||
|
|
||||||
|
class PaymentTransformer extends TransformerAbstract
|
||||||
|
{
|
||||||
|
public function transform($data, $maps)
|
||||||
|
{
|
||||||
|
return new Item($data, function ($data) use ($maps) {
|
||||||
|
return [
|
||||||
|
'amount' => $data->paid,
|
||||||
|
'payment_date_sql' => $data->create_date,
|
||||||
|
'client_id' => $data->client_id,
|
||||||
|
'invoice_id' => $data->invoice_id,
|
||||||
|
];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -1,88 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* Created by PhpStorm.
|
|
||||||
* User: eduardocruz
|
|
||||||
* Date: 11/9/15
|
|
||||||
* Time: 11:47
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace app\Ninja\Import\FreshBooks;
|
|
||||||
|
|
||||||
use League\Fractal\TransformerAbstract;
|
|
||||||
use League\Fractal\Resource\Collection;
|
|
||||||
use stdClass;
|
|
||||||
use Illuminate\Support\Facades\Auth;
|
|
||||||
use Exception;
|
|
||||||
|
|
||||||
class StaffTransformer extends TransformerAbstract
|
|
||||||
{
|
|
||||||
public function transform($data)
|
|
||||||
{
|
|
||||||
return new Collection($data, function(array $data) {
|
|
||||||
$data = $this->arrayToObject($data);
|
|
||||||
return [
|
|
||||||
'account_id' => Auth::user()->account_id,
|
|
||||||
'first_name' => $data->fname !== array() ? $data->fname : '',
|
|
||||||
'last_name' => $data->lname !== array() ? $data->lname : '',
|
|
||||||
'phone' => $data->bus_phone !== array() ? $data->bus_phone : $data->mob_phone,
|
|
||||||
'username' => $data->email !== array() ? $data->email : '',
|
|
||||||
'email' => $data->email !== array() ? $data->email : '',
|
|
||||||
];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private function arrayToObject($array)
|
|
||||||
{
|
|
||||||
$object = new stdClass();
|
|
||||||
$object->fname = $array[0];
|
|
||||||
$object->lname = $array[1];
|
|
||||||
$object->email = $array[2];
|
|
||||||
$object->p_stret = $array[3];
|
|
||||||
$object->p_street2 = $array[4];
|
|
||||||
$object->p_city = $array[5];
|
|
||||||
$object->p_province = $array[6];
|
|
||||||
$object->p_country = $array[7];
|
|
||||||
$object->p_code = $array[8];
|
|
||||||
$object->bus_phone = $array[9];
|
|
||||||
$object->home_phone = $array[10];
|
|
||||||
$object->mob_phone = $array[11];
|
|
||||||
$object->fax = $array[12];
|
|
||||||
$object->s_street = $array[13];
|
|
||||||
$object->s_street2 = $array[14];
|
|
||||||
$object->s_city = $array[15];
|
|
||||||
$object->s_province = $array[16];
|
|
||||||
$object->s_country = $array[17];
|
|
||||||
$object->s_code = $array[18];
|
|
||||||
return $object;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function validateHeader($csvHeader)
|
|
||||||
{
|
|
||||||
$header = [0 => "fname",
|
|
||||||
1 => "lname",
|
|
||||||
2 => "email",
|
|
||||||
3 => "p_stret",
|
|
||||||
4 => "p_street2",
|
|
||||||
5 => "p_city",
|
|
||||||
6 => "p_province",
|
|
||||||
7 => "p_country",
|
|
||||||
8 => "p_code",
|
|
||||||
9 => "bus_phone",
|
|
||||||
10 => "home_phone",
|
|
||||||
11 => "mob_phone",
|
|
||||||
12 => "fax",
|
|
||||||
13 => "s_street",
|
|
||||||
14 => "s_street2",
|
|
||||||
15 => "s_city",
|
|
||||||
16 => "s_province",
|
|
||||||
17 => "s_country",
|
|
||||||
18 => "s_code"];
|
|
||||||
|
|
||||||
if(empty($difference))
|
|
||||||
return;
|
|
||||||
|
|
||||||
$difference = array_diff($header, $csvHeader);
|
|
||||||
$difference = implode(',', $difference);
|
|
||||||
throw new Exception(trans('texts.invalid_csv_header') . " - $difference - ");
|
|
||||||
}
|
|
||||||
}
|
|
29
app/Ninja/Import/FreshBooks/TaskTransformer.php
Normal file
29
app/Ninja/Import/FreshBooks/TaskTransformer.php
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
<?php namespace App\Ninja\Import\FreshBooks;
|
||||||
|
|
||||||
|
use League\Fractal\TransformerAbstract;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
|
||||||
|
/*
|
||||||
|
class TaskTransformer extends TransformerAbstract
|
||||||
|
{
|
||||||
|
|
||||||
|
public function transform($data)
|
||||||
|
{
|
||||||
|
// start by converting to seconds
|
||||||
|
$seconds = ($data->hours * 3600);
|
||||||
|
$timeLogFinish = strtotime($data->date);
|
||||||
|
$timeLogStart = intval($timeLogFinish - $seconds);
|
||||||
|
$timeLog[] = [];
|
||||||
|
$timelog[] = $timeLogStart;
|
||||||
|
$timelog[] = $timeLogFinish;
|
||||||
|
$timeLog = json_encode(array($timelog));
|
||||||
|
|
||||||
|
return [
|
||||||
|
'action' => 'stop',
|
||||||
|
'time_log' => $timeLog,
|
||||||
|
'description' => $data->task,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
*/
|
@ -1,68 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* Created by PhpStorm.
|
|
||||||
* User: eduardocruz
|
|
||||||
* Date: 11/9/15
|
|
||||||
* Time: 11:47
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace app\Ninja\Import\FreshBooks;
|
|
||||||
|
|
||||||
use League\Fractal\TransformerAbstract;
|
|
||||||
use League\Fractal\Resource\Collection;
|
|
||||||
use stdClass;
|
|
||||||
use Illuminate\Support\Facades\Auth;
|
|
||||||
|
|
||||||
class TimesheetTransformer extends TransformerAbstract
|
|
||||||
{
|
|
||||||
|
|
||||||
public function transform($data)
|
|
||||||
{
|
|
||||||
return new Collection($data, function(array $data) {
|
|
||||||
$data = $this->arrayToObject($data);
|
|
||||||
// start by converting to seconds
|
|
||||||
$seconds = ($data->hours * 3600);
|
|
||||||
$timeLogFinish = strtotime($data->date);
|
|
||||||
$timeLogStart = intval($timeLogFinish - $seconds);
|
|
||||||
$timeLog[] = [];
|
|
||||||
$timelog[] = $timeLogStart;
|
|
||||||
$timelog[] = $timeLogFinish;
|
|
||||||
//dd(json_decode("[[$timeLogStart,$timeLogFinish]]"));
|
|
||||||
$timeLog = json_encode(array($timelog));
|
|
||||||
return [
|
|
||||||
'action' => 'stop',
|
|
||||||
'time_log' => $timeLog !== array() ? $timeLog : '',
|
|
||||||
'user_id' => Auth::user()->id,
|
|
||||||
'description' => $data->task !== array() ? $data->task : '',
|
|
||||||
];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private function arrayToObject($array)
|
|
||||||
{
|
|
||||||
$object = new stdClass();
|
|
||||||
$object->fname = $array[0];
|
|
||||||
$object->lname = $array[1];
|
|
||||||
$object->date = $array[2];
|
|
||||||
$object->project = $array[3];
|
|
||||||
$object->task = $array[4];
|
|
||||||
$object->hours = $array[5];
|
|
||||||
return $object;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function validateHeader($csvHeader)
|
|
||||||
{
|
|
||||||
$header = [
|
|
||||||
0 => "fname",
|
|
||||||
1 => "lname",
|
|
||||||
2 => "date",
|
|
||||||
3 => "project",
|
|
||||||
4 => "task",
|
|
||||||
5 => "hours"];
|
|
||||||
|
|
||||||
if(!empty(array_diff($header, $csvHeader)))
|
|
||||||
throw new Exception(trans('texts.invalid_csv_header'));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
@ -12,6 +12,15 @@ class ClientRepository extends BaseRepository
|
|||||||
return 'App\Models\Client';
|
return 'App\Models\Client';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function all()
|
||||||
|
{
|
||||||
|
return Client::scope()
|
||||||
|
->with('user', 'contacts', 'country')
|
||||||
|
->withTrashed()
|
||||||
|
->where('is_deleted', '=', false)
|
||||||
|
->get();
|
||||||
|
}
|
||||||
|
|
||||||
public function find($filter = null)
|
public function find($filter = null)
|
||||||
{
|
{
|
||||||
$query = \DB::table('clients')
|
$query = \DB::table('clients')
|
||||||
|
@ -22,6 +22,16 @@ class InvoiceRepository extends BaseRepository
|
|||||||
$this->paymentService = $paymentService;
|
$this->paymentService = $paymentService;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function all()
|
||||||
|
{
|
||||||
|
return Invoice::scope()
|
||||||
|
->with('user', 'client.contacts', 'invoice_status')
|
||||||
|
->withTrashed()
|
||||||
|
->where('is_quote', '=', false)
|
||||||
|
->where('is_recurring', '=', false)
|
||||||
|
->get();
|
||||||
|
}
|
||||||
|
|
||||||
public function getInvoices($accountId, $clientPublicId = false, $entityType = ENTITY_INVOICE, $filter = false)
|
public function getInvoices($accountId, $clientPublicId = false, $entityType = ENTITY_INVOICE, $filter = false)
|
||||||
{
|
{
|
||||||
$query = \DB::table('invoices')
|
$query = \DB::table('invoices')
|
||||||
@ -156,9 +166,15 @@ class InvoiceRepository extends BaseRepository
|
|||||||
$invoice->invoice_number = trim($data['invoice_number']);
|
$invoice->invoice_number = trim($data['invoice_number']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isset($data['discount'])) {
|
||||||
$invoice->discount = round(Utils::parseFloat($data['discount']), 2);
|
$invoice->discount = round(Utils::parseFloat($data['discount']), 2);
|
||||||
|
}
|
||||||
|
if (isset($data['is_amount_discount'])) {
|
||||||
$invoice->is_amount_discount = $data['is_amount_discount'] ? true : false;
|
$invoice->is_amount_discount = $data['is_amount_discount'] ? true : false;
|
||||||
|
}
|
||||||
|
if (isset($data['partial'])) {
|
||||||
$invoice->partial = round(Utils::parseFloat($data['partial']), 2);
|
$invoice->partial = round(Utils::parseFloat($data['partial']), 2);
|
||||||
|
}
|
||||||
$invoice->invoice_date = isset($data['invoice_date_sql']) ? $data['invoice_date_sql'] : Utils::toSqlDate($data['invoice_date']);
|
$invoice->invoice_date = isset($data['invoice_date_sql']) ? $data['invoice_date_sql'] : Utils::toSqlDate($data['invoice_date']);
|
||||||
|
|
||||||
if ($invoice->is_recurring) {
|
if ($invoice->is_recurring) {
|
||||||
@ -172,14 +188,16 @@ class InvoiceRepository extends BaseRepository
|
|||||||
$invoice->due_date = null;
|
$invoice->due_date = null;
|
||||||
$invoice->auto_bill = isset($data['auto_bill']) && $data['auto_bill'] ? true : false;
|
$invoice->auto_bill = isset($data['auto_bill']) && $data['auto_bill'] ? true : false;
|
||||||
} else {
|
} else {
|
||||||
|
if (isset($data['due_date']) || isset($data['due_date_sql'])) {
|
||||||
$invoice->due_date = isset($data['due_date_sql']) ? $data['due_date_sql'] : Utils::toSqlDate($data['due_date']);
|
$invoice->due_date = isset($data['due_date_sql']) ? $data['due_date_sql'] : Utils::toSqlDate($data['due_date']);
|
||||||
|
}
|
||||||
$invoice->frequency_id = 0;
|
$invoice->frequency_id = 0;
|
||||||
$invoice->start_date = null;
|
$invoice->start_date = null;
|
||||||
$invoice->end_date = null;
|
$invoice->end_date = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
$invoice->terms = trim($data['terms']) ? trim($data['terms']) : (!$publicId && $account->invoice_terms ? $account->invoice_terms : '');
|
$invoice->terms = trim($data['terms']) ? trim($data['terms']) : (!$publicId && $account->invoice_terms ? $account->invoice_terms : '');
|
||||||
$invoice->invoice_footer = trim($data['invoice_footer']) ? trim($data['invoice_footer']) : (!$publicId && $account->invoice_footer ? $account->invoice_footer : '');
|
$invoice->invoice_footer = (isset($data['invoice_footer']) && trim($data['invoice_footer'])) ? trim($data['invoice_footer']) : (!$publicId && $account->invoice_footer ? $account->invoice_footer : '');
|
||||||
$invoice->public_notes = trim($data['public_notes']);
|
$invoice->public_notes = trim($data['public_notes']);
|
||||||
|
|
||||||
// process date variables
|
// process date variables
|
||||||
@ -188,7 +206,7 @@ class InvoiceRepository extends BaseRepository
|
|||||||
$invoice->public_notes = Utils::processVariables($invoice->public_notes);
|
$invoice->public_notes = Utils::processVariables($invoice->public_notes);
|
||||||
|
|
||||||
$invoice->po_number = trim($data['po_number']);
|
$invoice->po_number = trim($data['po_number']);
|
||||||
$invoice->invoice_design_id = $data['invoice_design_id'];
|
$invoice->invoice_design_id = isset($data['invoice_design_id']) ? $data['invoice_design_id'] : $account->invoice_design_id;
|
||||||
|
|
||||||
if (isset($data['tax_name']) && isset($data['tax_rate']) && $data['tax_name']) {
|
if (isset($data['tax_name']) && isset($data['tax_rate']) && $data['tax_name']) {
|
||||||
$invoice->tax_rate = Utils::parseFloat($data['tax_rate']);
|
$invoice->tax_rate = Utils::parseFloat($data['tax_rate']);
|
||||||
@ -306,7 +324,7 @@ class InvoiceRepository extends BaseRepository
|
|||||||
$task->invoice_id = $invoice->id;
|
$task->invoice_id = $invoice->id;
|
||||||
$task->client_id = $invoice->client_id;
|
$task->client_id = $invoice->client_id;
|
||||||
$task->save();
|
$task->save();
|
||||||
} else if ($item['product_key'] && !$invoice->has_tasks) {
|
} else if (isset($item['product_key']) && $item['product_key'] && !$invoice->has_tasks) {
|
||||||
$product = Product::findProductByKey(trim($item['product_key']));
|
$product = Product::findProductByKey(trim($item['product_key']));
|
||||||
|
|
||||||
if (\Auth::user()->account->update_products) {
|
if (\Auth::user()->account->update_products) {
|
||||||
@ -323,7 +341,7 @@ class InvoiceRepository extends BaseRepository
|
|||||||
|
|
||||||
$invoiceItem = InvoiceItem::createNew();
|
$invoiceItem = InvoiceItem::createNew();
|
||||||
$invoiceItem->product_id = isset($product) ? $product->id : null;
|
$invoiceItem->product_id = isset($product) ? $product->id : null;
|
||||||
$invoiceItem->product_key = trim($invoice->is_recurring ? $item['product_key'] : Utils::processVariables($item['product_key']));
|
$invoiceItem->product_key = isset($item['product_key']) ? (trim($invoice->is_recurring ? $item['product_key'] : Utils::processVariables($item['product_key']))) : '';
|
||||||
$invoiceItem->notes = trim($invoice->is_recurring ? $item['notes'] : Utils::processVariables($item['notes']));
|
$invoiceItem->notes = trim($invoice->is_recurring ? $item['notes'] : Utils::processVariables($item['notes']));
|
||||||
$invoiceItem->cost = Utils::parseFloat($item['cost']);
|
$invoiceItem->cost = Utils::parseFloat($item['cost']);
|
||||||
$invoiceItem->qty = Utils::parseFloat($item['qty']);
|
$invoiceItem->qty = Utils::parseFloat($item['qty']);
|
||||||
|
@ -116,10 +116,12 @@ class PaymentRepository extends BaseRepository
|
|||||||
$payment->payment_date = date('Y-m-d');
|
$payment->payment_date = date('Y-m-d');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isset($input['transaction_reference'])) {
|
||||||
$payment->transaction_reference = trim($input['transaction_reference']);
|
$payment->transaction_reference = trim($input['transaction_reference']);
|
||||||
|
}
|
||||||
|
|
||||||
if (!$publicId) {
|
if (!$publicId) {
|
||||||
$clientId = Client::getPrivateId($input['client']);
|
$clientId = Client::getPrivateId(isset($input['client_id']) ? $input['client_id'] : $input['client']);
|
||||||
$amount = Utils::parseFloat($input['amount']);
|
$amount = Utils::parseFloat($input['amount']);
|
||||||
|
|
||||||
if ($paymentTypeId == PAYMENT_TYPE_CREDIT) {
|
if ($paymentTypeId == PAYMENT_TYPE_CREDIT) {
|
||||||
@ -137,8 +139,10 @@ class PaymentRepository extends BaseRepository
|
|||||||
}
|
}
|
||||||
|
|
||||||
$payment->client_id = $clientId;
|
$payment->client_id = $clientId;
|
||||||
$payment->invoice_id = isset($input['invoice']) && $input['invoice'] != "-1" ? Invoice::getPrivateId($input['invoice']) : null;
|
|
||||||
$payment->amount = $amount;
|
$payment->amount = $amount;
|
||||||
|
|
||||||
|
$invoicePublicId = isset($input['invoice_id']) ? $input['invoice_id'] : $input['invoice'];
|
||||||
|
$payment->invoice_id = Invoice::getPrivateId($invoicePublicId);
|
||||||
}
|
}
|
||||||
|
|
||||||
$payment->save();
|
$payment->save();
|
||||||
|
119
app/Services/ImportService.php
Normal file
119
app/Services/ImportService.php
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
<?php namespace App\Services;
|
||||||
|
|
||||||
|
use Excel;
|
||||||
|
use Cache;
|
||||||
|
use Exception;
|
||||||
|
use League\Fractal\Manager;
|
||||||
|
use App\Ninja\Repositories\ClientRepository;
|
||||||
|
use App\Ninja\Repositories\InvoiceRepository;
|
||||||
|
use App\Ninja\Repositories\PaymentRepository;
|
||||||
|
use App\Ninja\Serializers\ArraySerializer;
|
||||||
|
|
||||||
|
class ImportService
|
||||||
|
{
|
||||||
|
protected $transformer;
|
||||||
|
protected $invoiceRepo;
|
||||||
|
protected $clientRepo;
|
||||||
|
|
||||||
|
public static $entityTypes = [
|
||||||
|
ENTITY_CLIENT,
|
||||||
|
ENTITY_INVOICE,
|
||||||
|
ENTITY_TASK,
|
||||||
|
];
|
||||||
|
|
||||||
|
public static $sources = [
|
||||||
|
IMPORT_CSV,
|
||||||
|
IMPORT_FRESHBOOKS,
|
||||||
|
//IMPORT_HARVEST,
|
||||||
|
//IMPORT_HIVEAGE,
|
||||||
|
//IMPORT_INVOICEABLE,
|
||||||
|
//IMPORT_NUTCACHE,
|
||||||
|
//IMPORT_RONIN,
|
||||||
|
//IMPORT_WAVE,
|
||||||
|
//IMPORT_ZOHO,
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FreshBooksDataImporterService constructor.
|
||||||
|
*/
|
||||||
|
public function __construct(Manager $manager, ClientRepository $clientRepo, InvoiceRepository $invoiceRepo, PaymentRepository $paymentRepo)
|
||||||
|
{
|
||||||
|
$this->fractal = $manager;
|
||||||
|
$this->fractal->setSerializer(new ArraySerializer());
|
||||||
|
|
||||||
|
$this->clientRepo = $clientRepo;
|
||||||
|
$this->invoiceRepo = $invoiceRepo;
|
||||||
|
$this->paymentRepo = $paymentRepo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function import($source, $files)
|
||||||
|
{
|
||||||
|
$imported_files = null;
|
||||||
|
|
||||||
|
foreach ($files as $entityType => $file) {
|
||||||
|
$this->execute($source, $entityType, $file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function execute($source, $entityType, $file)
|
||||||
|
{
|
||||||
|
$transformerClassName = $this->getTransformerClassName($source, $entityType);
|
||||||
|
$transformer = new $transformerClassName;
|
||||||
|
|
||||||
|
Excel::load($file, function($reader) use ($source, $entityType, $transformer) {
|
||||||
|
|
||||||
|
$maps = $this->createMaps();
|
||||||
|
|
||||||
|
$reader->each(function($row) use ($source, $entityType, $transformer, $maps) {
|
||||||
|
if ($resource = $transformer->transform($row, $maps)) {
|
||||||
|
$data = $this->fractal->createData($resource)->toArray();
|
||||||
|
$entity = $this->{"{$entityType}Repo"}->save($data);
|
||||||
|
|
||||||
|
// if the invoice is paid we'll also create a payment record
|
||||||
|
if ($entityType === ENTITY_INVOICE && isset($data['paid']) && $data['paid']) {
|
||||||
|
$class = self::getTransformerClassName($source, 'payment');
|
||||||
|
$paymentTransformer = new $class;
|
||||||
|
$row->client_id = $data['client_id'];
|
||||||
|
$row->invoice_id = $entity->public_id;
|
||||||
|
if ($resource = $paymentTransformer->transform($row, $maps)) {
|
||||||
|
$data = $this->fractal->createData($resource)->toArray();
|
||||||
|
$this->paymentRepo->save($data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private function createMaps()
|
||||||
|
{
|
||||||
|
$clientMap = [];
|
||||||
|
$clients = $this->clientRepo->all();
|
||||||
|
foreach ($clients as $client) {
|
||||||
|
$clientMap[$client->name] = $client->public_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
$invoiceMap = [];
|
||||||
|
$invoices = $this->invoiceRepo->all();
|
||||||
|
foreach ($invoices as $invoice) {
|
||||||
|
$invoiceMap[$invoice->invoice_number] = $invoice->public_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
$countryMap = [];
|
||||||
|
$countries = Cache::get('countries');
|
||||||
|
foreach ($countries as $country) {
|
||||||
|
$countryMap[$country->name] = $country->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
ENTITY_CLIENT => $clientMap,
|
||||||
|
ENTITY_INVOICE => $invoiceMap,
|
||||||
|
'countries' => $countryMap,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getTransformerClassName($source, $entityType)
|
||||||
|
{
|
||||||
|
return 'App\\Ninja\\Import\\' . $source . '\\' . ucwords($entityType) . 'Transformer';
|
||||||
|
}
|
||||||
|
}
|
@ -434,7 +434,7 @@ class ConfideSetupUsersTable extends Migration {
|
|||||||
Schema::create('payments', function($t)
|
Schema::create('payments', function($t)
|
||||||
{
|
{
|
||||||
$t->increments('id');
|
$t->increments('id');
|
||||||
$t->unsignedInteger('invoice_id')->nullable();
|
$t->unsignedInteger('invoice_id')->index();
|
||||||
$t->unsignedInteger('account_id')->index();
|
$t->unsignedInteger('account_id')->index();
|
||||||
$t->unsignedInteger('client_id')->index();
|
$t->unsignedInteger('client_id')->index();
|
||||||
$t->unsignedInteger('contact_id')->nullable();
|
$t->unsignedInteger('contact_id')->nullable();
|
||||||
|
@ -115,7 +115,8 @@ class PaymentLibrariesSeeder extends Seeder
|
|||||||
['name' => 'Mexican Peso', 'code' => 'MXN', 'symbol' => '$', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
|
['name' => 'Mexican Peso', 'code' => 'MXN', 'symbol' => '$', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
|
||||||
['name' => 'Egyptian Pound', 'code' => 'EGP', 'symbol' => '£', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
|
['name' => 'Egyptian Pound', 'code' => 'EGP', 'symbol' => '£', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
|
||||||
['name' => 'Colombian Peso', 'code' => 'COP', 'symbol' => '$', 'precision' => '2', 'thousand_separator' => '.', 'decimal_separator' => ','],
|
['name' => 'Colombian Peso', 'code' => 'COP', 'symbol' => '$', 'precision' => '2', 'thousand_separator' => '.', 'decimal_separator' => ','],
|
||||||
['name' => 'West African Franc', 'code' => 'XOF', 'symbol' => 'CFA ', 'precision' => '2', 'thousand_separator' => '.', 'decimal_separator' => ','],
|
['name' => 'West African Franc', 'code' => 'XOF', 'symbol' => 'CFA ', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
|
||||||
|
['name' => 'Chinese Renminbi', 'code' => 'CNY', 'symbol' => 'RMB ', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
|
||||||
];
|
];
|
||||||
|
|
||||||
foreach ($currencies as $currency) {
|
foreach ($currencies as $currency) {
|
||||||
|
4
public/css/built.css
vendored
4
public/css/built.css
vendored
@ -3378,3 +3378,7 @@ ul.user-accounts a:hover div.remove {
|
|||||||
content: "";
|
content: "";
|
||||||
background-color: #e37329;
|
background-color: #e37329;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
div.panel-body div.panel-body {
|
||||||
|
padding-bottom: 0px;
|
||||||
|
}
|
4
public/css/style.css
vendored
4
public/css/style.css
vendored
@ -1027,3 +1027,7 @@ ul.user-accounts a:hover div.remove {
|
|||||||
content: "";
|
content: "";
|
||||||
background-color: #e37329;
|
background-color: #e37329;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
div.panel-body div.panel-body {
|
||||||
|
padding-bottom: 0px;
|
||||||
|
}
|
@ -207,15 +207,8 @@ return array(
|
|||||||
|
|
||||||
//import CSV data pages
|
//import CSV data pages
|
||||||
'import_clients' => 'Import Client Data',
|
'import_clients' => 'Import Client Data',
|
||||||
'import_from_freshbooks' => 'Import From FreshBooks',
|
'csv_file' => 'CSV file',
|
||||||
'csv_file' => 'Select CSV file',
|
|
||||||
'csv_client_file' => 'Select CSV Client file',
|
|
||||||
'csv_invoice_file' => 'Select CSV Invoice file',
|
|
||||||
'csv_timesheet_file' => 'Select CSV Timesheet file',
|
|
||||||
'export_clients' => 'Export Client Data',
|
'export_clients' => 'Export Client Data',
|
||||||
'no_mapper' => 'No valid mapping for file',
|
|
||||||
'invalid_csv_header' => 'Invalid CSV Header',
|
|
||||||
|
|
||||||
|
|
||||||
// application messages
|
// application messages
|
||||||
'created_client' => 'Successfully created client',
|
'created_client' => 'Successfully created client',
|
||||||
@ -796,7 +789,7 @@ return array(
|
|||||||
'invoice_not_found' => 'The requested invoice is not available',
|
'invoice_not_found' => 'The requested invoice is not available',
|
||||||
|
|
||||||
'referral_program' => 'Referral Program',
|
'referral_program' => 'Referral Program',
|
||||||
'referral_code' => 'Referral Code',
|
'referral_code' => 'Referral URL',
|
||||||
'last_sent_on' => 'Sent Last: :date',
|
'last_sent_on' => 'Sent Last: :date',
|
||||||
|
|
||||||
'page_expire' => 'This page will expire soon, :click_here to keep working',
|
'page_expire' => 'This page will expire soon, :click_here to keep working',
|
||||||
@ -929,6 +922,16 @@ return array(
|
|||||||
'include' => 'Include',
|
'include' => 'Include',
|
||||||
|
|
||||||
'logo_too_large' => 'Your logo is :size, for better performance we suggest uploading an image file less than 200KB',
|
'logo_too_large' => 'Your logo is :size, for better performance we suggest uploading an image file less than 200KB',
|
||||||
|
'import_freshbooks' => 'Import From FreshBooks',
|
||||||
|
'import_data' => 'Import Data',
|
||||||
|
'source' => 'Source',
|
||||||
|
'csv' => 'CSV',
|
||||||
|
'client_file' => 'Client File',
|
||||||
|
'invoice_file' => 'Invoice File',
|
||||||
|
'task_file' => 'Task File',
|
||||||
|
'no_mapper' => 'No valid mapping for file',
|
||||||
|
'invalid_csv_header' => 'Invalid CSV Header',
|
||||||
|
|
||||||
'email_errors' => [
|
'email_errors' => [
|
||||||
'inactive_client' => 'Emails can not be sent to inactive clients',
|
'inactive_client' => 'Emails can not be sent to inactive clients',
|
||||||
'inactive_contact' => 'Emails can not be sent to inactive contacts',
|
'inactive_contact' => 'Emails can not be sent to inactive contacts',
|
||||||
|
@ -1,35 +1,44 @@
|
|||||||
@extends('header')
|
@extends('header')
|
||||||
|
|
||||||
|
@section('head')
|
||||||
|
@parent
|
||||||
|
|
||||||
|
<style type="text/css">
|
||||||
|
.client-file,
|
||||||
|
.task-file {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
@stop
|
||||||
|
|
||||||
|
|
||||||
@section('content')
|
@section('content')
|
||||||
@parent
|
@parent
|
||||||
|
|
||||||
@include('accounts.nav', ['selected' => ACCOUNT_IMPORT_EXPORT])
|
@include('accounts.nav', ['selected' => ACCOUNT_IMPORT_EXPORT])
|
||||||
|
|
||||||
{!! Former::open_for_files('settings/' . ACCOUNT_MAP) !!}
|
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<h3 class="panel-title">{!! trans('texts.import_clients') !!}</h3>
|
<h3 class="panel-title">{!! trans('texts.import_data') !!}</h3>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
{!! Former::file('file')->label(trans('texts.csv_file')) !!}
|
|
||||||
{!! Former::actions( Button::info(trans('texts.upload'))->submit()->large()->appendIcon(Icon::create('open'))) !!}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{!! Former::close() !!}
|
|
||||||
|
|
||||||
{!! Former::open_for_files('settings/' . IMPORT_FROM_FRESHBOOKS) !!}
|
{!! Former::open_for_files('/import') !!}
|
||||||
<div class="panel panel-default">
|
{!! Former::select('source')
|
||||||
<div class="panel-heading">
|
->onchange('setFileTypesVisible()')
|
||||||
<h3 class="panel-title">{!! trans('texts.import_from_freshbooks') !!}</h3>
|
->options(array_combine(\App\Services\ImportService::$sources, \App\Services\ImportService::$sources))
|
||||||
</div>
|
->style('width: 200px') !!}
|
||||||
<div class="panel-body">
|
|
||||||
{!! Former::file('client_file')->label(trans('texts.csv_client_file')) !!}
|
@foreach (\App\Services\ImportService::$entityTypes as $entityType)
|
||||||
{!! Former::file('invoice_file')->label(trans('texts.csv_invoice_file')) !!}
|
{!! Former::file("{$entityType}_file")
|
||||||
{!! Former::file('timesheet_file')->label(trans('texts.csv_timesheet_file')) !!}
|
->addGroupClass("{$entityType}-file") !!}
|
||||||
|
@endforeach
|
||||||
|
|
||||||
{!! Former::actions( Button::info(trans('texts.upload'))->submit()->large()->appendIcon(Icon::create('open'))) !!}
|
{!! Former::actions( Button::info(trans('texts.upload'))->submit()->large()->appendIcon(Icon::create('open'))) !!}
|
||||||
|
{!! Former::close() !!}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{!! Former::close() !!}
|
|
||||||
|
|
||||||
|
|
||||||
{!! Former::open('/export') !!}
|
{!! Former::open('/export') !!}
|
||||||
@ -115,6 +124,26 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setFileTypesVisible() {
|
||||||
|
var val = $('#source').val();
|
||||||
|
@foreach (\App\Services\ImportService::$entityTypes as $entityType)
|
||||||
|
$('.{{ $entityType }}-file').hide();
|
||||||
|
@endforeach
|
||||||
|
@foreach (\App\Services\ImportService::$sources as $source)
|
||||||
|
if (val === '{{ $source }}') {
|
||||||
|
@if ($source == IMPORT_CSV)
|
||||||
|
$('.client-file').show();
|
||||||
|
@else
|
||||||
|
@foreach (\App\Services\ImportService::$entityTypes as $entityType)
|
||||||
|
@if (class_exists(\App\Services\ImportService::getTransformerClassName($source, $entityType)))
|
||||||
|
$('.{{ $entityType }}-file').show();
|
||||||
|
@endif
|
||||||
|
@endforeach
|
||||||
|
@endif
|
||||||
|
}
|
||||||
|
@endforeach
|
||||||
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@stop
|
@stop
|
@ -51,11 +51,10 @@
|
|||||||
@if ($user->referral_code)
|
@if ($user->referral_code)
|
||||||
{{ Former::setOption('capitalize_translations', false) }}
|
{{ Former::setOption('capitalize_translations', false) }}
|
||||||
{!! Former::plaintext('referral_code')
|
{!! Former::plaintext('referral_code')
|
||||||
->help(NINJA_APP_URL . '/invoice_now?rc=' . $user->referral_code)
|
->help($referralCounts['free'] . ' ' . trans('texts.free') . ' | ' .
|
||||||
->value($user->referral_code . ' - '.
|
$referralCounts['pro'] . ' ' . trans('texts.pro') .
|
||||||
$referralCounts['free'] . ' ' . trans('texts.free') . ' | ' .
|
'<a href="'.REFERRAL_PROGRAM_URL.'" target="_blank" title="'.trans('texts.learn_more').'">' . Icon::create('question-sign') . '</a> ')
|
||||||
$referralCounts['pro'] . ' ' . trans('texts.pro') . ' ' .
|
->value(NINJA_APP_URL . '/invoice_now?rc=' . $user->referral_code) !!}
|
||||||
'<a href="'.REFERRAL_PROGRAM_URL.'" target="_blank" title="'.trans('texts.learn_more').'">' . Icon::create('question-sign') . '</a>') !!}
|
|
||||||
@else
|
@else
|
||||||
{!! Former::checkbox('referral_code')
|
{!! Former::checkbox('referral_code')
|
||||||
->help(trans('texts.referral_code_help'))
|
->help(trans('texts.referral_code_help'))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user