mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2024-11-09 12:42:36 +01:00
Support multiple migrations at once
This commit is contained in:
parent
c4b147d7c8
commit
d24d2e4b93
@ -2,22 +2,9 @@
|
||||
|
||||
namespace App\Http\Controllers\Migration;
|
||||
|
||||
use App\Models\User;
|
||||
use App\Models\Credit;
|
||||
use App\Models\Contact;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\Payment;
|
||||
use App\Models\Product;
|
||||
use App\Models\TaxRate;
|
||||
use App\Libraries\Utils;
|
||||
use App\Models\Document;
|
||||
use App\Models\PaymentMethod;
|
||||
use App\Models\AccountGateway;
|
||||
use App\Models\AccountGatewayToken;
|
||||
use App\Traits\GenerateMigrationResources;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Crypt;
|
||||
use App\Models\AccountGatewaySettings;
|
||||
use App\Services\Migration\AuthService;
|
||||
use App\Http\Controllers\BaseController;
|
||||
use App\Services\Migration\CompanyService;
|
||||
@ -26,6 +13,7 @@ use App\Http\Requests\MigrationTypeRequest;
|
||||
use App\Services\Migration\CompleteService;
|
||||
use App\Http\Requests\MigrationEndpointRequest;
|
||||
use App\Http\Requests\MigrationCompaniesRequest;
|
||||
use App\Models\Account;
|
||||
|
||||
class StepsController extends BaseController
|
||||
{
|
||||
@ -159,10 +147,9 @@ class StepsController extends BaseController
|
||||
);
|
||||
}
|
||||
|
||||
$companyService = (new CompanyService(session('MIGRATION_ACCOUNT_TOKEN')))
|
||||
->endpoint(session('MIGRATION_ENDPOINT'))
|
||||
$companyService = (new CompanyService())
|
||||
->start();
|
||||
|
||||
|
||||
if ($companyService->isSuccessful()) {
|
||||
return view('migration.companies', ['companies' => $companyService->getCompanies()]);
|
||||
}
|
||||
@ -180,15 +167,12 @@ class StepsController extends BaseController
|
||||
);
|
||||
}
|
||||
|
||||
foreach ($request->companies as $company) {
|
||||
(new CompleteService(session('MIGRATION_ACCOUNT_TOKEN')))
|
||||
->file($this->getMigrationFile())
|
||||
->force(array_key_exists('force', $company))
|
||||
->company($company['id'])
|
||||
->endpoint(session('MIGRATION_ENDPOINT'))
|
||||
->companyKey($request->account_key)
|
||||
->start();
|
||||
}
|
||||
$migrationData = $this->generateMigrationData($request->all());
|
||||
|
||||
$completeService = (new CompleteService(session('MIGRATION_ACCOUNT_TOKEN')))
|
||||
->data($migrationData)
|
||||
->endpoint(session('MIGRATION_ENDPOINT'))
|
||||
->start();
|
||||
|
||||
return view('migration.completed');
|
||||
}
|
||||
@ -224,51 +208,61 @@ class StepsController extends BaseController
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getMigrationFile()
|
||||
public function generateMigrationData(array $data): array
|
||||
{
|
||||
$this->account = Auth::user()->account;
|
||||
$migrationData = [];
|
||||
|
||||
$date = date('Y-m-d');
|
||||
$accountKey = $this->account->account_key;
|
||||
foreach ($data['companies'] as $company) {
|
||||
$account = Account::where('account_key', $company['id'])->firstOrFail();
|
||||
|
||||
$output = fopen('php://output', 'w') or Utils::fatalError();
|
||||
$this->account = $account;
|
||||
|
||||
$fileName = "{$accountKey}-{$date}-invoiceninja";
|
||||
$date = date('Y-m-d');
|
||||
$accountKey = $this->account->account_key;
|
||||
|
||||
$data = [
|
||||
'company' => $this->getCompany(),
|
||||
'users' => $this->getUsers(),
|
||||
'tax_rates' => $this->getTaxRates(),
|
||||
'payment_terms' => $this->getPaymentTerms(),
|
||||
'clients' => $this->getClients(),
|
||||
'vendors' => $this->getVendors(),
|
||||
'projects' => $this->getProjects(),
|
||||
'products' => $this->getProducts(),
|
||||
'invoices' => $this->getInvoices(),
|
||||
'recurring_invoices' => $this->getRecurringInvoices(),
|
||||
'quotes' => $this->getQuotes(),
|
||||
'credits' => $this->getCreditsNotes(),
|
||||
'payments' => array_merge($this->getPayments(), $this->getCredits()),
|
||||
'documents' => $this->getDocuments(),
|
||||
'company_gateways' => $this->getCompanyGateways(),
|
||||
'client_gateway_tokens' => $this->getClientGatewayTokens(),
|
||||
'expense_categories' => $this->getExpenseCategories(),
|
||||
'task_statuses' => $this->getTaskStatuses(),
|
||||
'expenses' => $this->getExpenses(),
|
||||
'tasks' => $this->getTasks(),
|
||||
];
|
||||
$output = fopen('php://output', 'w') or Utils::fatalError();
|
||||
|
||||
$file = storage_path("migrations/{$fileName}.zip");
|
||||
$fileName = "{$accountKey}-{$date}-invoiceninja";
|
||||
|
||||
$zip = new \ZipArchive();
|
||||
$zip->open($file, \ZipArchive::CREATE | \ZipArchive::OVERWRITE);
|
||||
$zip->addFromString('migration.json', json_encode($data, JSON_PRETTY_PRINT));
|
||||
$zip->close();
|
||||
$migrationData[$company['id']]['data'] = [
|
||||
'company' => $this->getCompany(),
|
||||
'users' => $this->getUsers(),
|
||||
'tax_rates' => $this->getTaxRates(),
|
||||
'payment_terms' => $this->getPaymentTerms(),
|
||||
'clients' => $this->getClients(),
|
||||
'vendors' => $this->getVendors(),
|
||||
'projects' => $this->getProjects(),
|
||||
'products' => $this->getProducts(),
|
||||
'invoices' => $this->getInvoices(),
|
||||
'recurring_invoices' => $this->getRecurringInvoices(),
|
||||
'quotes' => $this->getQuotes(),
|
||||
'credits' => $this->getCreditsNotes(),
|
||||
'payments' => array_merge($this->getPayments(), $this->getCredits()),
|
||||
'documents' => $this->getDocuments(),
|
||||
'company_gateways' => $this->getCompanyGateways(),
|
||||
'client_gateway_tokens' => $this->getClientGatewayTokens(),
|
||||
'expense_categories' => $this->getExpenseCategories(),
|
||||
'task_statuses' => $this->getTaskStatuses(),
|
||||
'expenses' => $this->getExpenses(),
|
||||
'tasks' => $this->getTasks(),
|
||||
];
|
||||
|
||||
$migrationData[$company['id']]['force'] = array_key_exists('force', $company) ? true : false;
|
||||
|
||||
$file = storage_path("migrations/{$fileName}.zip");
|
||||
|
||||
$zip = new \ZipArchive();
|
||||
$zip->open($file, \ZipArchive::CREATE | \ZipArchive::OVERWRITE);
|
||||
$zip->addFromString('migration.json', json_encode($data, JSON_PRETTY_PRINT));
|
||||
$zip->close();
|
||||
|
||||
$migrationData[$company['id']]['file'] = $file;
|
||||
}
|
||||
|
||||
return $migrationData;
|
||||
|
||||
// header('Content-Type: application/zip');
|
||||
// header('Content-Length: ' . filesize($file));
|
||||
// header("Content-Disposition: attachment; filename={$fileName}.zip");
|
||||
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
|
@ -2,46 +2,34 @@
|
||||
|
||||
namespace App\Services\Migration;
|
||||
|
||||
use App\Models\Account;
|
||||
use Unirest\Request;
|
||||
use Unirest\Request\Body;
|
||||
|
||||
class CompanyService
|
||||
{
|
||||
protected $token;
|
||||
protected $endpoint = 'https://app.invoiceninja.com';
|
||||
protected $uri = '/api/v1/companies';
|
||||
protected $errors = [];
|
||||
protected $isSuccessful;
|
||||
protected $companies = [];
|
||||
|
||||
|
||||
public function __construct(string $token)
|
||||
{
|
||||
$this->token = $token;
|
||||
}
|
||||
|
||||
public function endpoint(string $endpoint)
|
||||
{
|
||||
$this->endpoint = $endpoint;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function start()
|
||||
{
|
||||
$response = Request::get($this->getUrl(), $this->getHeaders());
|
||||
try {
|
||||
foreach (session(SESSION_USER_ACCOUNTS) as $company) {
|
||||
$account = Account::find($company->account_id);
|
||||
|
||||
if ($response->code == 200) {
|
||||
$this->isSuccessful = true;
|
||||
|
||||
foreach($response->body->data as $company) {
|
||||
$this->companies[] = $company;
|
||||
if ($account) {
|
||||
$this->companies[] = [
|
||||
'id' => $company->account_id,
|
||||
'name' => $account->name,
|
||||
'company_key' => $account->account_key,
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (in_array($response->code, [401, 422, 500])) {
|
||||
$this->isSuccessful = true;
|
||||
} catch (\Exception $th) {
|
||||
$this->isSuccessful = false;
|
||||
$this->processErrors($response->body);
|
||||
$this->errors = [];
|
||||
}
|
||||
|
||||
return $this;
|
||||
@ -61,29 +49,8 @@ class CompanyService
|
||||
return [];
|
||||
}
|
||||
|
||||
|
||||
public function getErrors()
|
||||
{
|
||||
return $this->errors;
|
||||
}
|
||||
|
||||
private function getHeaders()
|
||||
{
|
||||
return [
|
||||
'X-Requested-With' => 'XMLHttpRequest',
|
||||
'X-Api-Token' => $this->token,
|
||||
];
|
||||
}
|
||||
|
||||
private function getUrl()
|
||||
{
|
||||
return $this->endpoint . $this->uri;
|
||||
}
|
||||
|
||||
private function processErrors($errors)
|
||||
{
|
||||
$array = (array) $errors;
|
||||
|
||||
$this->errors = $array;
|
||||
}
|
||||
}
|
||||
|
@ -9,37 +9,25 @@ use Unirest\Request\Body;
|
||||
class CompleteService
|
||||
{
|
||||
protected $token;
|
||||
protected $company;
|
||||
protected $file;
|
||||
|
||||
protected $endpoint = 'https://app.invoiceninja.com';
|
||||
|
||||
protected $uri = '/api/v1/migration/start/';
|
||||
|
||||
protected $errors = [];
|
||||
|
||||
protected $isSuccessful;
|
||||
protected $force = false;
|
||||
protected $companyKey;
|
||||
|
||||
protected $data;
|
||||
|
||||
public function __construct(string $token)
|
||||
{
|
||||
$this->token = $token;
|
||||
}
|
||||
|
||||
public function file($file)
|
||||
public function data(array $data)
|
||||
{
|
||||
$this->file = $file;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function force($option)
|
||||
{
|
||||
$this->force = $option;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function company($company)
|
||||
{
|
||||
$this->company = $company;
|
||||
$this->data = $data;
|
||||
|
||||
return $this;
|
||||
}
|
||||
@ -51,26 +39,30 @@ class CompleteService
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function companyKey(string $key)
|
||||
{
|
||||
$this->companyKey = $key;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function start()
|
||||
{
|
||||
$body = [
|
||||
'migration' => \Unirest\Request\Body::file($this->file, 'application/zip'),
|
||||
'force' => $this->force,
|
||||
'company_key' => $this->companyKey,
|
||||
'companies' => [],
|
||||
];
|
||||
|
||||
$response = Request::post($this->getUrl(), $this->getHeaders(), $body);
|
||||
foreach ($this->data as $companyKey => $companyData) {
|
||||
$body['companies'][] = [
|
||||
'company_key' => $companyKey,
|
||||
'migration' => \Unirest\Request\Body::file($companyData['file'], 'application/zip'),
|
||||
'force' => $companyData['force'],
|
||||
];
|
||||
}
|
||||
|
||||
try {
|
||||
$response = Request::post($this->getUrl(), $this->getHeaders(), json_encode($body));
|
||||
|
||||
dd($response);
|
||||
} catch (\Exception $e) {
|
||||
dd($e->getMessage());
|
||||
}
|
||||
|
||||
if ($response->code == 200) {
|
||||
$this->isSuccessful = true;
|
||||
$this->deleteFile();
|
||||
}
|
||||
|
||||
if (in_array($response->code, [401, 422, 500])) {
|
||||
@ -88,7 +80,6 @@ class CompleteService
|
||||
return $this->isSuccessful;
|
||||
}
|
||||
|
||||
|
||||
public function getErrors()
|
||||
{
|
||||
return $this->errors;
|
||||
@ -105,11 +96,11 @@ class CompleteService
|
||||
|
||||
private function getUrl()
|
||||
{
|
||||
return $this->endpoint . $this->uri . $this->company;
|
||||
return "{$this->endpoint}/{$this->uri}";
|
||||
}
|
||||
|
||||
public function deleteFile()
|
||||
public function deleteFile(string $path)
|
||||
{
|
||||
Storage::delete($this->file);
|
||||
Storage::delete($path);
|
||||
}
|
||||
}
|
||||
|
@ -3790,7 +3790,9 @@ $LANG = array(
|
||||
'tax_name1' => 'Tax Name 1',
|
||||
'tax_name2' => 'Tax Name 2',
|
||||
'transaction_id' => 'Transaction ID',
|
||||
);
|
||||
'migration_select_company_label' => 'Awesome! Please select the companies you would like to migrate.',
|
||||
'force_migration' => 'Force migration',
|
||||
);
|
||||
|
||||
return $LANG;
|
||||
|
||||
|
@ -11,22 +11,23 @@
|
||||
<h3 class="panel-title">{!! trans('texts.welcome_to_the_new_version') !!}</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<h4>Awesome! Please select the company you would like to apply migration.</h4>
|
||||
<h4>{!! trans('texts.migration_select_company_label') !!}</h4>
|
||||
<form action="{{ url('/migration/companies') }}" method="post" id="auth-form">
|
||||
{{ csrf_field() }}
|
||||
<input type="hidden" name="account_key" value="{{ auth()->user()->account->account_key }}">
|
||||
|
||||
|
||||
@foreach($companies as $company)
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" id="company_{{ $company->id }}" type="checkbox" name="companies[{{ $company->id }}][id]" id="company1" value="{{ $company->id }}" checked>
|
||||
<label class="form-check-label" for="company_{{ $company->id }}">
|
||||
Name: {{ $company->settings->name }} ID: {{ $company->id }}
|
||||
<input class="form-check-input" id="{{ $company['company_key'] }}" type="checkbox" name="companies[{{ $company['company_key'] }}][id]" value="{{ $company['company_key'] }}">
|
||||
<label class="form-check-label" for="{{ $company['company_key'] }}">
|
||||
{{ $company['name'] }}
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="checkbox" name="companies[{{ $company->id }}][force]">
|
||||
<label for="force">Force migration</label>
|
||||
<small>* All current company data will be wiped.</small>
|
||||
<label for="companies[{{ $company['company_key'] }}][force]">
|
||||
<input type="checkbox" id="companies[{{ $company['company_key'] }}][force]" name="companies[{{ $company['company_key'] }}][force]">
|
||||
<small>{!! trans('texts.force_migration') !!}</small>
|
||||
</label>
|
||||
</div>
|
||||
@endforeach
|
||||
</form>
|
||||
|
Loading…
Reference in New Issue
Block a user