mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-07-08 05:34:30 -04:00
Support importing JSON file
This commit is contained in:
parent
e312f00b80
commit
0acf4ff1fc
@ -43,10 +43,12 @@ class ExportController extends BaseController
|
|||||||
$manager->setSerializer(new ArraySerializer());
|
$manager->setSerializer(new ArraySerializer());
|
||||||
|
|
||||||
$account = Auth::user()->account;
|
$account = Auth::user()->account;
|
||||||
$account->loadAllData();
|
$account->load(['clients.contacts', 'clients.invoices.payments', 'clients.invoices.invoice_items']);
|
||||||
|
|
||||||
$resource = new Item($account, new AccountTransformer);
|
$resource = new Item($account, new AccountTransformer);
|
||||||
$data = $manager->createData($resource)->toArray();
|
$data = $manager->parseIncludes('clients.invoices.payments')
|
||||||
|
->createData($resource)
|
||||||
|
->toArray();
|
||||||
|
|
||||||
return response()->json($data);
|
return response()->json($data);
|
||||||
}
|
}
|
||||||
|
@ -36,8 +36,11 @@ class ImportController extends BaseController
|
|||||||
if ($source === IMPORT_CSV) {
|
if ($source === IMPORT_CSV) {
|
||||||
$data = $this->importService->mapCSV($files);
|
$data = $this->importService->mapCSV($files);
|
||||||
return View::make('accounts.import_map', ['data' => $data]);
|
return View::make('accounts.import_map', ['data' => $data]);
|
||||||
|
} elseif ($source === IMPORT_JSON) {
|
||||||
|
$results = $this->importService->importJSON($files[IMPORT_JSON]);
|
||||||
|
return $this->showResult($results);
|
||||||
} else {
|
} else {
|
||||||
$results = $this->importService->import($source, $files);
|
$results = $this->importService->importFiles($source, $files);
|
||||||
return $this->showResult($results);
|
return $this->showResult($results);
|
||||||
}
|
}
|
||||||
} catch (Exception $exception) {
|
} catch (Exception $exception) {
|
||||||
|
@ -25,12 +25,12 @@ class CreatePaymentRequest extends PaymentRequest
|
|||||||
$invoice = Invoice::scope($input['invoice'])->firstOrFail();
|
$invoice = Invoice::scope($input['invoice'])->firstOrFail();
|
||||||
|
|
||||||
$rules = array(
|
$rules = array(
|
||||||
'client' => 'required',
|
'client' => 'required', // TODO: change to client_id once views are updated
|
||||||
'invoice' => 'required',
|
'invoice' => 'required', // TODO: change to invoice_id once views are updated
|
||||||
'amount' => "required|less_than:{$invoice->balance}|positive",
|
'amount' => "required|less_than:{$invoice->balance}|positive",
|
||||||
);
|
);
|
||||||
|
|
||||||
if ($input['payment_type_id'] == PAYMENT_TYPE_CREDIT) {
|
if ( ! empty($input['payment_type_id']) && $input['payment_type_id'] == PAYMENT_TYPE_CREDIT) {
|
||||||
$rules['payment_type_id'] = 'has_credit:'.$input['client'].','.$input['amount'];
|
$rules['payment_type_id'] = 'has_credit:'.$input['client'].','.$input['amount'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -472,6 +472,7 @@ if (!defined('CONTACT_EMAIL')) {
|
|||||||
define('DEFAULT_SEND_RECURRING_HOUR', 8);
|
define('DEFAULT_SEND_RECURRING_HOUR', 8);
|
||||||
|
|
||||||
define('IMPORT_CSV', 'CSV');
|
define('IMPORT_CSV', 'CSV');
|
||||||
|
define('IMPORT_JSON', 'JSON');
|
||||||
define('IMPORT_FRESHBOOKS', 'FreshBooks');
|
define('IMPORT_FRESHBOOKS', 'FreshBooks');
|
||||||
define('IMPORT_WAVE', 'Wave');
|
define('IMPORT_WAVE', 'Wave');
|
||||||
define('IMPORT_RONIN', 'Ronin');
|
define('IMPORT_RONIN', 'Ronin');
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
use Auth;
|
use Auth;
|
||||||
use Utils;
|
use Utils;
|
||||||
|
|
||||||
|
use App\Models\EntityModel;
|
||||||
use App\Events\ClientWasCreated;
|
use App\Events\ClientWasCreated;
|
||||||
use App\Events\QuoteWasCreated;
|
use App\Events\QuoteWasCreated;
|
||||||
use App\Events\InvoiceWasCreated;
|
use App\Events\InvoiceWasCreated;
|
||||||
@ -63,6 +64,10 @@ class SubscriptionListener
|
|||||||
|
|
||||||
private function checkSubscriptions($eventId, $entity, $transformer, $include = '')
|
private function checkSubscriptions($eventId, $entity, $transformer, $include = '')
|
||||||
{
|
{
|
||||||
|
if ( ! EntityModel::$notifySubscriptions) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
$subscription = $entity->account->getSubscription($eventId);
|
$subscription = $entity->account->getSubscription($eventId);
|
||||||
|
|
||||||
if ($subscription) {
|
if ($subscription) {
|
||||||
|
@ -545,7 +545,7 @@ class Account extends Eloquent
|
|||||||
|
|
||||||
if ($this->hasClientNumberPattern($invoice) && !$clientId) {
|
if ($this->hasClientNumberPattern($invoice) && !$clientId) {
|
||||||
// do nothing, we don't yet know the value
|
// do nothing, we don't yet know the value
|
||||||
} else {
|
} elseif ( ! $invoice->invoice_number) {
|
||||||
$invoice->invoice_number = $this->getNextInvoiceNumber($invoice);
|
$invoice->invoice_number = $this->getNextInvoiceNumber($invoice);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -649,7 +649,7 @@ class Account extends Eloquent
|
|||||||
return $this->getNextInvoiceNumber($invoice);
|
return $this->getNextInvoiceNumber($invoice);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getNextInvoiceNumber($invoice)
|
public function getNextInvoiceNumber($invoice, $validateUnique = true)
|
||||||
{
|
{
|
||||||
if ($this->hasNumberPattern($invoice->invoice_type_id)) {
|
if ($this->hasNumberPattern($invoice->invoice_type_id)) {
|
||||||
$number = $this->getNumberPattern($invoice);
|
$number = $this->getNumberPattern($invoice);
|
||||||
@ -657,13 +657,16 @@ class Account extends Eloquent
|
|||||||
$counter = $this->getCounter($invoice->invoice_type_id);
|
$counter = $this->getCounter($invoice->invoice_type_id);
|
||||||
$prefix = $this->getNumberPrefix($invoice->invoice_type_id);
|
$prefix = $this->getNumberPrefix($invoice->invoice_type_id);
|
||||||
$counterOffset = 0;
|
$counterOffset = 0;
|
||||||
|
$check = false;
|
||||||
|
|
||||||
// confirm the invoice number isn't already taken
|
// confirm the invoice number isn't already taken
|
||||||
do {
|
do {
|
||||||
$number = $prefix . str_pad($counter, $this->invoice_number_padding, '0', STR_PAD_LEFT);
|
$number = $prefix . str_pad($counter, $this->invoice_number_padding, '0', STR_PAD_LEFT);
|
||||||
|
if ($validateUnique) {
|
||||||
$check = Invoice::scope(false, $this->id)->whereInvoiceNumber($number)->withTrashed()->first();
|
$check = Invoice::scope(false, $this->id)->whereInvoiceNumber($number)->withTrashed()->first();
|
||||||
$counter++;
|
$counter++;
|
||||||
$counterOffset++;
|
$counterOffset++;
|
||||||
|
}
|
||||||
} while ($check);
|
} while ($check);
|
||||||
|
|
||||||
// update the invoice counter to be caught up
|
// update the invoice counter to be caught up
|
||||||
@ -688,7 +691,7 @@ class Account extends Eloquent
|
|||||||
public function incrementCounter($invoice)
|
public function incrementCounter($invoice)
|
||||||
{
|
{
|
||||||
// if they didn't use the counter don't increment it
|
// if they didn't use the counter don't increment it
|
||||||
if ($invoice->invoice_number != $this->getNextInvoiceNumber($invoice)) {
|
if ($invoice->invoice_number != $this->getNextInvoiceNumber($invoice, false)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1452,6 +1455,14 @@ class Account extends Eloquent
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Account::updated(function ($account) {
|
Account::updated(function ($account)
|
||||||
|
{
|
||||||
|
// prevent firing event if the invoice/quote counter was changed
|
||||||
|
// TODO: remove once counters are moved to separate table
|
||||||
|
$dirty = $account->getDirty();
|
||||||
|
if (isset($dirty['invoice_number_counter']) || isset($dirty['quote_number_counter'])) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Event::fire(new UserSettingsChanged());
|
Event::fire(new UserSettingsChanged());
|
||||||
});
|
});
|
||||||
|
@ -9,21 +9,30 @@ class EntityModel extends Eloquent
|
|||||||
public $timestamps = true;
|
public $timestamps = true;
|
||||||
protected $hidden = ['id'];
|
protected $hidden = ['id'];
|
||||||
|
|
||||||
|
public static $notifySubscriptions = true;
|
||||||
|
|
||||||
public static function createNew($context = null)
|
public static function createNew($context = null)
|
||||||
{
|
{
|
||||||
$className = get_called_class();
|
$className = get_called_class();
|
||||||
$entity = new $className();
|
$entity = new $className();
|
||||||
|
|
||||||
if ($context) {
|
if ($context) {
|
||||||
$entity->user_id = $context instanceof User ? $context->id : $context->user_id;
|
$user = $context instanceof User ? $context : $context->user;
|
||||||
$entity->account_id = $context->account_id;
|
$account = $context->account;
|
||||||
} elseif (Auth::check()) {
|
} elseif (Auth::check()) {
|
||||||
$entity->user_id = Auth::user()->id;
|
$user = Auth::user();
|
||||||
$entity->account_id = Auth::user()->account_id;
|
$account = Auth::user()->account;
|
||||||
} else {
|
} else {
|
||||||
Utils::fatalError();
|
Utils::fatalError();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$entity->user_id = $user->id;
|
||||||
|
$entity->account_id = $account->id;
|
||||||
|
|
||||||
|
// store references to the original user/account to prevent needing to reload them
|
||||||
|
$entity->setRelation('user', $user);
|
||||||
|
$entity->setRelation('account', $account);
|
||||||
|
|
||||||
if (method_exists($className, 'withTrashed')){
|
if (method_exists($className, 'withTrashed')){
|
||||||
$lastEntity = $className::withTrashed()
|
$lastEntity = $className::withTrashed()
|
||||||
->scope(false, $entity->account_id);
|
->scope(false, $entity->account_id);
|
||||||
|
@ -5,9 +5,9 @@ use League\Fractal\Resource\Item;
|
|||||||
|
|
||||||
class PaymentTransformer extends BaseTransformer
|
class PaymentTransformer extends BaseTransformer
|
||||||
{
|
{
|
||||||
public function transform($data, $maps)
|
public function transform($data)
|
||||||
{
|
{
|
||||||
return new Item($data, function ($data) use ($maps) {
|
return new Item($data, function ($data) {
|
||||||
return [
|
return [
|
||||||
'amount' => $data->paid,
|
'amount' => $data->paid,
|
||||||
'payment_date_sql' => $data->create_date,
|
'payment_date_sql' => $data->create_date,
|
||||||
|
@ -5,9 +5,9 @@ use League\Fractal\Resource\Item;
|
|||||||
|
|
||||||
class PaymentTransformer extends BaseTransformer
|
class PaymentTransformer extends BaseTransformer
|
||||||
{
|
{
|
||||||
public function transform($data, $maps)
|
public function transform($data)
|
||||||
{
|
{
|
||||||
return new Item($data, function ($data) use ($maps) {
|
return new Item($data, function ($data) {
|
||||||
return [
|
return [
|
||||||
'amount' => $data->paid_total,
|
'amount' => $data->paid_total,
|
||||||
'payment_date_sql' => $this->getDate($data->last_paid_on),
|
'payment_date_sql' => $this->getDate($data->last_paid_on),
|
||||||
|
@ -5,9 +5,9 @@ use League\Fractal\Resource\Item;
|
|||||||
|
|
||||||
class PaymentTransformer extends BaseTransformer
|
class PaymentTransformer extends BaseTransformer
|
||||||
{
|
{
|
||||||
public function transform($data, $maps)
|
public function transform($data)
|
||||||
{
|
{
|
||||||
return new Item($data, function ($data) use ($maps) {
|
return new Item($data, function ($data) {
|
||||||
return [
|
return [
|
||||||
'amount' => $data->paid,
|
'amount' => $data->paid,
|
||||||
'payment_date_sql' => $data->date_paid,
|
'payment_date_sql' => $data->date_paid,
|
||||||
|
@ -5,9 +5,9 @@ use League\Fractal\Resource\Item;
|
|||||||
|
|
||||||
class PaymentTransformer extends BaseTransformer
|
class PaymentTransformer extends BaseTransformer
|
||||||
{
|
{
|
||||||
public function transform($data, $maps)
|
public function transform($data)
|
||||||
{
|
{
|
||||||
return new Item($data, function ($data) use ($maps) {
|
return new Item($data, function ($data) {
|
||||||
return [
|
return [
|
||||||
'amount' => (float) $data->paid_to_date,
|
'amount' => (float) $data->paid_to_date,
|
||||||
'payment_date_sql' => $this->getDate($data->date),
|
'payment_date_sql' => $this->getDate($data->date),
|
||||||
|
@ -5,9 +5,9 @@ use League\Fractal\Resource\Item;
|
|||||||
|
|
||||||
class PaymentTransformer extends BaseTransformer
|
class PaymentTransformer extends BaseTransformer
|
||||||
{
|
{
|
||||||
public function transform($data, $maps)
|
public function transform($data)
|
||||||
{
|
{
|
||||||
return new Item($data, function ($data) use ($maps) {
|
return new Item($data, function ($data) {
|
||||||
return [
|
return [
|
||||||
'amount' => (float) $data->total - (float) $data->balance,
|
'amount' => (float) $data->total - (float) $data->balance,
|
||||||
'payment_date_sql' => $data->date_paid,
|
'payment_date_sql' => $data->date_paid,
|
||||||
|
@ -5,13 +5,13 @@ use League\Fractal\Resource\Item;
|
|||||||
|
|
||||||
class PaymentTransformer extends BaseTransformer
|
class PaymentTransformer extends BaseTransformer
|
||||||
{
|
{
|
||||||
public function transform($data, $maps)
|
public function transform($data)
|
||||||
{
|
{
|
||||||
if ( ! $this->getInvoiceClientId($data->invoice_num)) {
|
if ( ! $this->getInvoiceClientId($data->invoice_num)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Item($data, function ($data) use ($maps) {
|
return new Item($data, function ($data) {
|
||||||
return [
|
return [
|
||||||
'amount' => (float) $data->amount,
|
'amount' => (float) $data->amount,
|
||||||
'payment_date_sql' => $this->getDate($data->payment_date),
|
'payment_date_sql' => $this->getDate($data->payment_date),
|
||||||
|
@ -5,9 +5,9 @@ use League\Fractal\Resource\Item;
|
|||||||
|
|
||||||
class PaymentTransformer extends BaseTransformer
|
class PaymentTransformer extends BaseTransformer
|
||||||
{
|
{
|
||||||
public function transform($data, $maps)
|
public function transform($data)
|
||||||
{
|
{
|
||||||
return new Item($data, function ($data) use ($maps) {
|
return new Item($data, function ($data) {
|
||||||
return [
|
return [
|
||||||
'amount' => (float) $data->total - (float) $data->balance,
|
'amount' => (float) $data->total - (float) $data->balance,
|
||||||
'payment_date_sql' => $data->last_payment_date,
|
'payment_date_sql' => $data->last_payment_date,
|
||||||
|
@ -118,11 +118,13 @@ class ClientRepository extends BaseRepository
|
|||||||
$first = false;
|
$first = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( ! $client->wasRecentlyCreated) {
|
||||||
foreach ($client->contacts as $contact) {
|
foreach ($client->contacts as $contact) {
|
||||||
if (!in_array($contact->public_id, $contactIds)) {
|
if (!in_array($contact->public_id, $contactIds)) {
|
||||||
$contact->delete();
|
$contact->delete();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!$publicId || $publicId == '-1') {
|
if (!$publicId || $publicId == '-1') {
|
||||||
event(new ClientWasCreated($client));
|
event(new ClientWasCreated($client));
|
||||||
|
@ -494,6 +494,7 @@ class InvoiceRepository extends BaseRepository
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( ! $invoice->wasRecentlyCreated) {
|
||||||
foreach ($invoice->documents as $document){
|
foreach ($invoice->documents as $document){
|
||||||
if(!in_array($document->public_id, $document_ids)){
|
if(!in_array($document->public_id, $document_ids)){
|
||||||
// Removed
|
// Removed
|
||||||
@ -504,6 +505,7 @@ class InvoiceRepository extends BaseRepository
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
foreach ($data['invoice_items'] as $item) {
|
foreach ($data['invoice_items'] as $item) {
|
||||||
$item = (array) $item;
|
$item = (array) $item;
|
||||||
|
@ -11,7 +11,6 @@ class EventServiceProvider extends ServiceProvider {
|
|||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
protected $listen = [
|
protected $listen = [
|
||||||
|
|
||||||
// Clients
|
// Clients
|
||||||
'App\Events\ClientWasCreated' => [
|
'App\Events\ClientWasCreated' => [
|
||||||
'App\Listeners\ActivityListener@createdClient',
|
'App\Listeners\ActivityListener@createdClient',
|
||||||
@ -151,7 +150,6 @@ class EventServiceProvider extends ServiceProvider {
|
|||||||
'App\Events\UserSettingsChanged' => [
|
'App\Events\UserSettingsChanged' => [
|
||||||
'App\Listeners\HandleUserSettingsChanged',
|
'App\Listeners\HandleUserSettingsChanged',
|
||||||
],
|
],
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -17,6 +17,7 @@ use App\Ninja\Repositories\ProductRepository;
|
|||||||
use App\Ninja\Serializers\ArraySerializer;
|
use App\Ninja\Serializers\ArraySerializer;
|
||||||
use App\Models\Client;
|
use App\Models\Client;
|
||||||
use App\Models\Invoice;
|
use App\Models\Invoice;
|
||||||
|
use App\Models\EntityModel;
|
||||||
|
|
||||||
class ImportService
|
class ImportService
|
||||||
{
|
{
|
||||||
@ -25,9 +26,13 @@ class ImportService
|
|||||||
protected $clientRepo;
|
protected $clientRepo;
|
||||||
protected $contactRepo;
|
protected $contactRepo;
|
||||||
protected $productRepo;
|
protected $productRepo;
|
||||||
protected $processedRows = array();
|
protected $processedRows = [];
|
||||||
|
|
||||||
|
private $maps = [];
|
||||||
|
public $results = [];
|
||||||
|
|
||||||
public static $entityTypes = [
|
public static $entityTypes = [
|
||||||
|
IMPORT_JSON,
|
||||||
ENTITY_CLIENT,
|
ENTITY_CLIENT,
|
||||||
ENTITY_CONTACT,
|
ENTITY_CONTACT,
|
||||||
ENTITY_INVOICE,
|
ENTITY_INVOICE,
|
||||||
@ -39,6 +44,7 @@ class ImportService
|
|||||||
|
|
||||||
public static $sources = [
|
public static $sources = [
|
||||||
IMPORT_CSV,
|
IMPORT_CSV,
|
||||||
|
IMPORT_JSON,
|
||||||
IMPORT_FRESHBOOKS,
|
IMPORT_FRESHBOOKS,
|
||||||
//IMPORT_HARVEST,
|
//IMPORT_HARVEST,
|
||||||
IMPORT_HIVEAGE,
|
IMPORT_HIVEAGE,
|
||||||
@ -68,10 +74,70 @@ class ImportService
|
|||||||
$this->productRepo = $productRepo;
|
$this->productRepo = $productRepo;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function import($source, $files)
|
public function importJSON($file)
|
||||||
|
{
|
||||||
|
$this->init();
|
||||||
|
|
||||||
|
$file = file_get_contents($file);
|
||||||
|
$json = json_decode($file, true);
|
||||||
|
$json = $this->removeIdFields($json);
|
||||||
|
|
||||||
|
$this->checkClientCount(count($json['clients']));
|
||||||
|
|
||||||
|
foreach ($json['clients'] as $jsonClient) {
|
||||||
|
|
||||||
|
if ($this->validate($jsonClient, ENTITY_CLIENT) === true) {
|
||||||
|
$client = $this->clientRepo->save($jsonClient);
|
||||||
|
$this->addSuccess($client);
|
||||||
|
} else {
|
||||||
|
$this->addFailure(ENTITY_CLIENT, $jsonClient);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($jsonClient['invoices'] as $jsonInvoice) {
|
||||||
|
$jsonInvoice['client_id'] = $client->id;
|
||||||
|
if ($this->validate($jsonInvoice, ENTITY_INVOICE) === true) {
|
||||||
|
$invoice = $this->invoiceRepo->save($jsonInvoice);
|
||||||
|
$this->addSuccess($invoice);
|
||||||
|
} else {
|
||||||
|
$this->addFailure(ENTITY_INVOICE, $jsonInvoice);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($jsonInvoice['payments'] as $jsonPayment) {
|
||||||
|
$jsonPayment['client_id'] = $jsonPayment['client'] = $client->id; // TODO: change to client_id once views are updated
|
||||||
|
$jsonPayment['invoice_id'] = $jsonPayment['invoice'] = $invoice->id; // TODO: change to invoice_id once views are updated
|
||||||
|
if ($this->validate($jsonPayment, ENTITY_PAYMENT) === true) {
|
||||||
|
$payment = $this->paymentRepo->save($jsonPayment);
|
||||||
|
$this->addSuccess($payment);
|
||||||
|
} else {
|
||||||
|
$this->addFailure(ENTITY_PAYMENT, $jsonPayment);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->results;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function removeIdFields($array)
|
||||||
|
{
|
||||||
|
foreach ($array as $key => $val) {
|
||||||
|
if (is_array($val)) {
|
||||||
|
$array[$key] = $this->removeIdFields($val);
|
||||||
|
} elseif ($key === 'id') {
|
||||||
|
unset($array[$key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $array;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function importFiles($source, $files)
|
||||||
{
|
{
|
||||||
$results = [];
|
$results = [];
|
||||||
$imported_files = null;
|
$imported_files = null;
|
||||||
|
$this->initMaps();
|
||||||
|
|
||||||
foreach ($files as $entityType => $file) {
|
foreach ($files as $entityType => $file) {
|
||||||
$results[$entityType] = $this->execute($source, $entityType, $file);
|
$results[$entityType] = $this->execute($source, $entityType, $file);
|
||||||
@ -89,12 +155,12 @@ class ImportService
|
|||||||
|
|
||||||
// Convert the data
|
// Convert the data
|
||||||
$row_list = array();
|
$row_list = array();
|
||||||
$maps = $this->createMaps();
|
|
||||||
Excel::load($file, function ($reader) use ($source, $entityType, $maps, &$row_list, &$results) {
|
Excel::load($file, function ($reader) use ($source, $entityType, &$row_list, &$results) {
|
||||||
$this->checkData($entityType, count($reader->all()));
|
$this->checkData($entityType, count($reader->all()));
|
||||||
|
|
||||||
$reader->each(function ($row) use ($source, $entityType, $maps, &$row_list, &$results) {
|
$reader->each(function ($row) use ($source, $entityType, &$row_list, &$results) {
|
||||||
$data_index = $this->transformRow($source, $entityType, $row, $maps);
|
$data_index = $this->transformRow($source, $entityType, $row);
|
||||||
|
|
||||||
if ($data_index !== false) {
|
if ($data_index !== false) {
|
||||||
if ($data_index !== true) {
|
if ($data_index !== true) {
|
||||||
@ -109,7 +175,7 @@ class ImportService
|
|||||||
|
|
||||||
// Save the data
|
// Save the data
|
||||||
foreach ($row_list as $row_data) {
|
foreach ($row_list as $row_data) {
|
||||||
$result = $this->saveData($source, $entityType, $row_data['row'], $row_data['data_index'], $maps);
|
$result = $this->saveData($source, $entityType, $row_data['row'], $row_data['data_index']);
|
||||||
if ($result) {
|
if ($result) {
|
||||||
$results[RESULT_SUCCESS][] = $result;
|
$results[RESULT_SUCCESS][] = $result;
|
||||||
} else {
|
} else {
|
||||||
@ -120,10 +186,10 @@ class ImportService
|
|||||||
return $results;
|
return $results;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function transformRow($source, $entityType, $row, $maps)
|
private function transformRow($source, $entityType, $row)
|
||||||
{
|
{
|
||||||
$transformer = $this->getTransformer($source, $entityType, $maps);
|
$transformer = $this->getTransformer($source, $entityType, $this->maps);
|
||||||
$resource = $transformer->transform($row, $maps);
|
$resource = $transformer->transform($row);
|
||||||
|
|
||||||
if (!$resource) {
|
if (!$resource) {
|
||||||
return false;
|
return false;
|
||||||
@ -138,7 +204,7 @@ class ImportService
|
|||||||
$data['invoice_number'] = $account->getNextInvoiceNumber($invoice);
|
$data['invoice_number'] = $account->getNextInvoiceNumber($invoice);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->validate($source, $data, $entityType) !== true) {
|
if ($this->validate($data, $entityType) !== true) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -160,14 +226,18 @@ class ImportService
|
|||||||
return key($this->processedRows);
|
return key($this->processedRows);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function saveData($source, $entityType, $row, $data_index, $maps)
|
private function saveData($source, $entityType, $row, $data_index)
|
||||||
{
|
{
|
||||||
$data = $this->processedRows[$data_index];
|
$data = $this->processedRows[$data_index];
|
||||||
$entity = $this->{"{$entityType}Repo"}->save($data);
|
$entity = $this->{"{$entityType}Repo"}->save($data);
|
||||||
|
|
||||||
|
// update the entity maps
|
||||||
|
$mapFunction = 'add' . ucwords($entity->getEntityType()) . 'ToMaps';
|
||||||
|
$this->$mapFunction($entity);
|
||||||
|
|
||||||
// if the invoice is paid we'll also create a payment record
|
// if the invoice is paid we'll also create a payment record
|
||||||
if ($entityType === ENTITY_INVOICE && isset($data['paid']) && $data['paid'] > 0) {
|
if ($entityType === ENTITY_INVOICE && isset($data['paid']) && $data['paid'] > 0) {
|
||||||
$this->createPayment($source, $row, $maps, $data['client_id'], $entity->id);
|
$this->createPayment($source, $row, $data['client_id'], $entity->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $entity;
|
return $entity;
|
||||||
@ -200,21 +270,22 @@ class ImportService
|
|||||||
return new $className($maps);
|
return new $className($maps);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function createPayment($source, $data, $maps, $clientId, $invoiceId)
|
private function createPayment($source, $data, $clientId, $invoiceId)
|
||||||
{
|
{
|
||||||
$paymentTransformer = $this->getTransformer($source, ENTITY_PAYMENT, $maps);
|
$paymentTransformer = $this->getTransformer($source, ENTITY_PAYMENT, $this->maps);
|
||||||
|
|
||||||
$data->client_id = $clientId;
|
$data->client_id = $clientId;
|
||||||
$data->invoice_id = $invoiceId;
|
$data->invoice_id = $invoiceId;
|
||||||
|
|
||||||
if ($resource = $paymentTransformer->transform($data, $maps)) {
|
if ($resource = $paymentTransformer->transform($data)) {
|
||||||
$data = $this->fractal->createData($resource)->toArray();
|
$data = $this->fractal->createData($resource)->toArray();
|
||||||
$this->paymentRepo->save($data);
|
$this->paymentRepo->save($data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function validate($source, $data, $entityType)
|
private function validate($data, $entityType)
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
// Harvest's contacts are listed separately
|
// Harvest's contacts are listed separately
|
||||||
if ($entityType === ENTITY_CLIENT && $source != IMPORT_HARVEST) {
|
if ($entityType === ENTITY_CLIENT && $source != IMPORT_HARVEST) {
|
||||||
$rules = [
|
$rules = [
|
||||||
@ -234,71 +305,21 @@ class ImportService
|
|||||||
'product_key' => 'required',
|
'product_key' => 'required',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
$requestClass = 'App\\Http\\Requests\\Create' . ucwords($entityType) . 'Request';
|
||||||
|
$request = new $requestClass();
|
||||||
|
$request->setUserResolver(function() { return Auth::user(); });
|
||||||
|
$request->replace($data);
|
||||||
|
|
||||||
$validator = Validator::make($data, $rules);
|
$validator = Validator::make($data, $request->rules());
|
||||||
|
|
||||||
if ($validator->fails()) {
|
if ($validator->fails()) {
|
||||||
$messages = $validator->messages();
|
return $validator->messages()->first();
|
||||||
|
|
||||||
return $messages->first();
|
|
||||||
} else {
|
} else {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function createMaps()
|
|
||||||
{
|
|
||||||
$clientMap = [];
|
|
||||||
$clients = $this->clientRepo->all();
|
|
||||||
foreach ($clients as $client) {
|
|
||||||
if ($name = strtolower(trim($client->name))) {
|
|
||||||
$clientMap[$name] = $client->id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$invoiceMap = [];
|
|
||||||
$invoiceClientMap = [];
|
|
||||||
$invoices = $this->invoiceRepo->all();
|
|
||||||
foreach ($invoices as $invoice) {
|
|
||||||
if ($number = strtolower(trim($invoice->invoice_number))) {
|
|
||||||
$invoiceMap[$number] = $invoice->id;
|
|
||||||
$invoiceClientMap[$number] = $invoice->client_id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$productMap = [];
|
|
||||||
$products = $this->productRepo->all();
|
|
||||||
foreach ($products as $product) {
|
|
||||||
if ($key = strtolower(trim($product->product_key))) {
|
|
||||||
$productMap[$key] = $product->id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$countryMap = [];
|
|
||||||
$countryMap2 = [];
|
|
||||||
$countries = Cache::get('countries');
|
|
||||||
foreach ($countries as $country) {
|
|
||||||
$countryMap[strtolower($country->name)] = $country->id;
|
|
||||||
$countryMap2[strtolower($country->iso_3166_2)] = $country->id;
|
|
||||||
}
|
|
||||||
|
|
||||||
$currencyMap = [];
|
|
||||||
$currencies = Cache::get('currencies');
|
|
||||||
foreach ($currencies as $currency) {
|
|
||||||
$currencyMap[strtolower($currency->code)] = $currency->id;
|
|
||||||
}
|
|
||||||
|
|
||||||
return [
|
|
||||||
ENTITY_CLIENT => $clientMap,
|
|
||||||
ENTITY_INVOICE => $invoiceMap,
|
|
||||||
ENTITY_INVOICE.'_'.ENTITY_CLIENT => $invoiceClientMap,
|
|
||||||
ENTITY_PRODUCT => $productMap,
|
|
||||||
'countries' => $countryMap,
|
|
||||||
'countries2' => $countryMap2,
|
|
||||||
'currencies' => $currencyMap,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function mapCSV($files)
|
public function mapCSV($files)
|
||||||
{
|
{
|
||||||
$data = [];
|
$data = [];
|
||||||
@ -430,7 +451,7 @@ class ImportService
|
|||||||
|
|
||||||
$data = Session::get("{$entityType}-data");
|
$data = Session::get("{$entityType}-data");
|
||||||
$this->checkData($entityType, count($data));
|
$this->checkData($entityType, count($data));
|
||||||
$maps = $this->createMaps();
|
$this->initMaps();
|
||||||
|
|
||||||
// Convert the data
|
// Convert the data
|
||||||
$row_list = array();
|
$row_list = array();
|
||||||
@ -441,7 +462,7 @@ class ImportService
|
|||||||
}
|
}
|
||||||
|
|
||||||
$row = $this->convertToObject($entityType, $row, $map);
|
$row = $this->convertToObject($entityType, $row, $map);
|
||||||
$data_index = $this->transformRow($source, $entityType, $row, $maps);
|
$data_index = $this->transformRow($source, $entityType, $row);
|
||||||
|
|
||||||
if ($data_index !== false) {
|
if ($data_index !== false) {
|
||||||
if ($data_index !== true) {
|
if ($data_index !== true) {
|
||||||
@ -455,7 +476,7 @@ class ImportService
|
|||||||
|
|
||||||
// Save the data
|
// Save the data
|
||||||
foreach ($row_list as $row_data) {
|
foreach ($row_list as $row_data) {
|
||||||
$result = $this->saveData($source, $entityType, $row_data['row'], $row_data['data_index'], $maps);
|
$result = $this->saveData($source, $entityType, $row_data['row'], $row_data['data_index']);
|
||||||
|
|
||||||
if ($result) {
|
if ($result) {
|
||||||
$results[RESULT_SUCCESS][] = $result;
|
$results[RESULT_SUCCESS][] = $result;
|
||||||
@ -493,4 +514,93 @@ class ImportService
|
|||||||
|
|
||||||
return $obj;
|
return $obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function addSuccess($entity)
|
||||||
|
{
|
||||||
|
$this->results[$entity->getEntityType()][RESULT_SUCCESS][] = $entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function addFailure($entityType, $data)
|
||||||
|
{
|
||||||
|
$this->results[$entityType][RESULT_FAILURE][] = $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function init()
|
||||||
|
{
|
||||||
|
EntityModel::$notifySubscriptions = false;
|
||||||
|
|
||||||
|
foreach ([ENTITY_CLIENT, ENTITY_INVOICE, ENTITY_PAYMENT] as $entityType) {
|
||||||
|
$this->results[$entityType] = [
|
||||||
|
RESULT_SUCCESS => [],
|
||||||
|
RESULT_FAILURE => [],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function initMaps()
|
||||||
|
{
|
||||||
|
$this->init();
|
||||||
|
|
||||||
|
$this->maps = [
|
||||||
|
'client' => [],
|
||||||
|
'invoice' => [],
|
||||||
|
'invoice_client' => [],
|
||||||
|
'product' => [],
|
||||||
|
'countries' => [],
|
||||||
|
'countries2' => [],
|
||||||
|
'currencies' => [],
|
||||||
|
'client_ids' => [],
|
||||||
|
'invoice_ids' => [],
|
||||||
|
];
|
||||||
|
|
||||||
|
$clients = $this->clientRepo->all();
|
||||||
|
foreach ($clients as $client) {
|
||||||
|
$this->addClientToMaps($client);
|
||||||
|
}
|
||||||
|
|
||||||
|
$invoices = $this->invoiceRepo->all();
|
||||||
|
foreach ($invoices as $invoice) {
|
||||||
|
$this->addInvoiceToMaps($invoice);
|
||||||
|
}
|
||||||
|
|
||||||
|
$products = $this->productRepo->all();
|
||||||
|
foreach ($products as $product) {
|
||||||
|
$this->addProductToMaps($product);
|
||||||
|
}
|
||||||
|
|
||||||
|
$countries = Cache::get('countries');
|
||||||
|
foreach ($countries as $country) {
|
||||||
|
$this->maps['countries'][strtolower($country->name)] = $country->id;
|
||||||
|
$this->maps['countries2'][strtolower($country->iso_3166_2)] = $country->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
$currencies = Cache::get('currencies');
|
||||||
|
foreach ($currencies as $currency) {
|
||||||
|
$this->maps['currencies'][strtolower($currency->code)] = $currency->id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function addInvoiceToMaps($invoice)
|
||||||
|
{
|
||||||
|
if ($number = strtolower(trim($invoice->invoice_number))) {
|
||||||
|
$this->maps['invoice'][$number] = $invoice->id;
|
||||||
|
$this->maps['invoice_client'][$number] = $invoice->client_id;
|
||||||
|
$this->maps['invoice_ids'][$invoice->public_id] = $invoice->id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function addClientToMaps($client)
|
||||||
|
{
|
||||||
|
if ($name = strtolower(trim($client->name))) {
|
||||||
|
$this->maps['client'][$name] = $client->id;
|
||||||
|
$this->maps['client_ids'][$client->public_id] = $client->id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function addProductToMaps($product)
|
||||||
|
{
|
||||||
|
if ($key = strtolower(trim($product->product_key))) {
|
||||||
|
$this->maps['product'][$key] = $product->id;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1321,6 +1321,8 @@ $LANG = array(
|
|||||||
'products_will_create' => 'products will be created.',
|
'products_will_create' => 'products will be created.',
|
||||||
'product_key' => 'Product',
|
'product_key' => 'Product',
|
||||||
'created_products' => 'Successfully created :count product(s)',
|
'created_products' => 'Successfully created :count product(s)',
|
||||||
|
'export_help' => 'Use JSON if you plan to import the data into Invoice Ninja.',
|
||||||
|
'JSON_file' => 'JSON File',
|
||||||
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -53,7 +53,8 @@
|
|||||||
->addOption('CSV', 'CSV')
|
->addOption('CSV', 'CSV')
|
||||||
->addOption('XLS', 'XLS')
|
->addOption('XLS', 'XLS')
|
||||||
->addOption('JSON', 'JSON')
|
->addOption('JSON', 'JSON')
|
||||||
->style('max-width: 200px') !!}
|
->style('max-width: 200px')
|
||||||
|
->inlineHelp('export_help') !!}
|
||||||
|
|
||||||
{!! Former::checkbox('entity_types')
|
{!! Former::checkbox('entity_types')
|
||||||
->label('include')
|
->label('include')
|
||||||
@ -100,6 +101,11 @@
|
|||||||
@endif
|
@endif
|
||||||
@endforeach
|
@endforeach
|
||||||
}
|
}
|
||||||
|
@if ($source === IMPORT_JSON)
|
||||||
|
if (val === '{{ $source }}') {
|
||||||
|
$('.JSON-file').show();
|
||||||
|
}
|
||||||
|
@endif
|
||||||
@endforeach
|
@endforeach
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
<link href="{{ asset('favicon-v2.png') }}" rel="shortcut icon" type="image/png">
|
<link href="{{ asset('favicon-v2.png') }}" rel="shortcut icon" type="image/png">
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
<!-- Source: https://github.com/hillelcoren/invoice-ninja -->
|
<!-- Source: https://github.com/invoiceninja/invoiceninja -->
|
||||||
<!-- Version: {{ NINJA_VERSION }} -->
|
<!-- Version: {{ NINJA_VERSION }} -->
|
||||||
|
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
Loading…
x
Reference in New Issue
Block a user