1
0
mirror of https://github.com/invoiceninja/invoiceninja.git synced 2024-11-10 13:12:50 +01:00

Wave tests

This commit is contained in:
David Bomba 2022-02-10 13:02:02 +11:00
parent 0f0b1d96f2
commit a0439f23b2
10 changed files with 658 additions and 29 deletions

View File

@ -148,12 +148,12 @@ class BaseImport
public function ingest($data, $entity_type) public function ingest($data, $entity_type)
{ {
$count = 0; $count = 0;
nlog("record count = ".count($data));
foreach ($data as $key => $record) { foreach ($data as $key => $record) {
try { try {
$entity = $this->transformer->transform($record); $entity = $this->transformer->transform($record);
nlog($entity);
/** @var \App\Http\Requests\Request $request */ /** @var \App\Http\Requests\Request $request */
$request = new $this->request_name(); $request = new $this->request_name();
@ -174,6 +174,7 @@ class BaseImport
$this->getUserIDForRecord($entity) $this->getUserIDForRecord($entity)
) )
); );
nlog("saving {$entity->name}");
$entity->saveQuietly(); $entity->saveQuietly();
$count++; $count++;
@ -181,6 +182,8 @@ class BaseImport
} }
} catch (\Exception $ex) { } catch (\Exception $ex) {
nlog($e->getMessage());
if ($ex instanceof ImportException) { if ($ex instanceof ImportException) {
$message = $ex->getMessage(); $message = $ex->getMessage();
} else { } else {
@ -512,4 +515,25 @@ class BaseImport
NinjaMailerJob::dispatch($nmo); NinjaMailerJob::dispatch($nmo);
} }
public function preTransform(array $data, $entity_type)
{
if (empty($this->column_map[$entity_type])) {
return false;
}
if ($this->skip_header) {
array_shift($data);
}
//sort the array by key
$keys = $this->column_map[$entity_type];
ksort($keys);
$data = array_map(function ($row) use ($keys) {
return array_combine($keys, array_intersect_key($row, $keys));
}, $data);
return $data;
}
} }

View File

@ -237,27 +237,6 @@ class Csv extends BaseImport implements ImportInterface
} }
public function preTransform(array $data, $entity_type)
{
if (empty($this->column_map[$entity_type])) {
return false;
}
if ($this->skip_header) {
array_shift($data);
}
//sort the array by key
$keys = $this->column_map[$entity_type];
ksort($keys);
$data = array_map(function ($row) use ($keys) {
return array_combine($keys, array_intersect_key($row, $keys));
}, $data);
return $data;
}
public function transform(array $data) public function transform(array $data)
{ {
} }

View File

@ -15,8 +15,6 @@ interface ImportInterface
public function import(string $entity); public function import(string $entity);
public function preTransform(array $data, string $entity_type);
public function transform(array $data); public function transform(array $data);
public function client(); public function client();

View File

@ -1,4 +1,5 @@
<?php <?php
/** /**
* Invoice Ninja (https://invoiceninja.com). * Invoice Ninja (https://invoiceninja.com).
* *
@ -8,9 +9,81 @@
* *
* @license https://www.elastic.co/licensing/elastic-license * @license https://www.elastic.co/licensing/elastic-license
*/ */
namespace App\Import\Providers; namespace App\Import\Providers;
class Wave extends BaseImport use App\Factory\ClientFactory;
use App\Http\Requests\Client\StoreClientRequest;
use App\Import\Transformer\Wave\ClientTransformer;
use App\Models\Client;
use App\Repositories\ClientRepository;
class Wave extends BaseImport implements ImportInterface
{ {
} public array $entity_count = [];
public function import(string $entity)
{
if (
in_array($entity, [
'client',
// 'product',
// 'invoice',
// 'payment',
// 'vendor',
// 'expense',
])
) {
$this->{$entity}();
}
//collate any errors
$this->finalizeImport();
}
public function client()
{
$entity_type = 'client';
$data = $this->getCsvData($entity_type);
nlog($data);
$data = $this->preTransform($data, $entity_type);
nlog($data);
if (empty($data)) {
$this->entity_count['clients'] = 0;
return;
}
$this->request_name = StoreClientRequest::class;
$this->repository_name = ClientRepository::class;
$this->factory_name = ClientFactory::class;
$this->repository = app()->make($this->repository_name);
$this->repository->import_mode = true;
$this->transformer = new ClientTransformer($this->company);
$client_count = $this->ingest($data, $entity_type);
$this->entity_count['clients'] = $client_count;
nlog($this->entity_count);
}
public function transform(array $data){}
public function product() {}
public function invoice() {}
public function payment() {}
public function vendor() {}
public function expense() {}
}

View File

@ -14,6 +14,7 @@ namespace App\Import\Transformer;
use App\Factory\ProjectFactory; use App\Factory\ProjectFactory;
use App\Models\ClientContact; use App\Models\ClientContact;
use App\Models\Country; use App\Models\Country;
use App\Models\ExpenseCategory;
use App\Models\PaymentType; use App\Models\PaymentType;
use App\Models\User; use App\Models\User;
use App\Utils\Number; use App\Utils\Number;
@ -38,6 +39,11 @@ class BaseTransformer
return isset($data[$field]) && $data[$field] ? $data[$field] : ''; return isset($data[$field]) && $data[$field] ? $data[$field] : '';
} }
public function getValueOrNull($data, $field)
{
return isset($data[$field]) && $data[$field] ? $data[$field] : null;
}
public function getCurrencyByCode($data, $key = 'client.currency_id') public function getCurrencyByCode($data, $key = 'client.currency_id')
{ {
$code = array_key_exists($key, $data) ? $data[$key] : false; $code = array_key_exists($key, $data) ? $data[$key] : false;
@ -429,6 +435,20 @@ class BaseTransformer
return $ec ? $ec->id : null; return $ec ? $ec->id : null;
} }
public function getOrCreateExpenseCategry($name)
{
$ec = $this->getExpenseCategoryId($name);
if($ec)
return $ec;
$expense_category = ExpenseCategory::create($this->company->id, $this->company->owner()->id);
$expense_category->name = $name;
$expense_category->save();
return $expense_category->id;
}
/** /**
* @param $name * @param $name
* *
@ -473,4 +493,6 @@ class BaseTransformer
return $pt ? $pt->id : null; return $pt ? $pt->id : null;
} }
} }

View File

@ -26,7 +26,7 @@ class ClientTransformer extends BaseTransformer
*/ */
public function transform($data) public function transform($data)
{ {
if (isset($data->name) && $this->hasClient($data->name)) { if (isset($data->name) && $this->getString($data, 'client.name')) {
throw new ImportException('Client already exists'); throw new ImportException('Client already exists');
} }

View File

@ -0,0 +1,74 @@
<?php
/**
* Invoice Ninja (https://clientninja.com).
*
* @link https://github.com/clientninja/clientninja source repository
*
* @copyright Copyright (c) 2021. client Ninja LLC (https://clientninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/
namespace App\Import\Transformer\Wave;
use App\Import\ImportException;
use App\Import\Transformer\BaseTransformer;
use Illuminate\Support\Str;
/**
* Class ClientTransformer.
*/
class ClientTransformer extends BaseTransformer {
/**
* @param $data
*
* @return array|bool
*/
public function transform( $data ) {
if ( isset( $data['customer_name'] ) && $this->hasClient( $data['customer_name'] ) ) {
throw new ImportException('Client already exists');
}
$settings = new \stdClass;
$settings->currency_id = (string) $this->getCurrencyByCode( $data, 'customer_currency' );
if ( strval( $data['Payment Terms'] ?? '' ) > 0 ) {
$settings->payment_terms = $data['Payment Terms'];
}
return [
'company_id' => $this->company->id,
'name' => $this->getString( $data, 'customer_name' ),
'number' => $this->getValueOrNull( $data, 'account_number' ),
'work_phone' => $this->getString( $data, 'phone' ),
'website' => $this->getString( $data, 'website' ),
'country_id' => !empty( $data['country'] ) ? $this->getCountryId( $data['country'] ) : null,
'state' => $this->getString( $data, 'province/state' ),
'address1' => $this->getString( $data, 'address_line_1' ),
'address2' => $this->getString( $data, 'address_line_2' ),
'city' => $this->getString( $data, 'city' ),
'postal_code' => $this->getString( $data, 'postal_code/zip_code' ),
'shipping_country_id' => !empty( $data['ship-to_country'] ) ? $this->getCountryId( $data['country'] ) : null,
'shipping_state' => $this->getString( $data, 'ship-to_province/state' ),
'shipping_address1' => $this->getString( $data, 'ship-to_address_line_1' ),
'shipping_address2' => $this->getString( $data, 'ship-to_address_line_2' ),
'shipping_city' => $this->getString( $data, 'ship-to_city' ),
'shipping_postal_code' => $this->getString( $data, 'ship-to_postal_code/zip_code' ),
'public_notes' => $this->getString( $data, 'delivery_instructions' ),
'credit_balance' => 0,
'settings' =>$settings,
'client_hash' => Str::random( 40 ),
'contacts' => [
[
'first_name' => $this->getString( $data, 'contact_first_name' ),
'last_name' => $this->getString( $data, 'contact_last_name' ),
'email' => $this->getString( $data, 'email' ),
'phone' => $this->getString( $data, 'phone' ),
],
],
];
}
}

View File

@ -0,0 +1,45 @@
<?php
/**
* client Ninja (https://clientninja.com).
*
* @link https://github.com/clientninja/clientninja source repository
*
* @copyright Copyright (c) 2021. client Ninja LLC (https://clientninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/
namespace App\Import\Transformer\Waveaccounting;
use App\Import\ImportException;
use App\Import\Transformer\BaseTransformer;
/**
* Class ExpenseTransformer.
*/
class ExpenseTransformer extends BaseTransformer {
/**
* @param $line_items_data
*
* @return bool|array
*/
public function transform( $data ) {
$transformed = [
'company_id' => $this->company->id,
'vendor_id' => $this->getVendorId($vendor_name = $this->getString($data, 'vendor')),
'number' => $this->getString($data, 'invoice_number'),
'public_notes'=> $this->getString($data, 'description'),
'date' => date( 'Y-m-d', strtotime( $data['bill_date'] ) ) ?: now()->format('Y-m-d'), //27-01-2022
'currency_id' => $this->getCurrencyByCode( $data, 'currency' ),
'category_id' => $this->getOrCreateExpenseCategry($data['account']),
'amount' => $this->getFloat($data['quantity']) * $this->getFloat($data['amount']),
'tax_name1' => $this->getTaxName($data['taxes']),
'tax_rate1' => $this->getTaxRate($data['taxes']),
];
return $transformed;
}
}

View File

@ -0,0 +1,80 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/clientninja/clientninja source repository
*
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://clientninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/
namespace App\Import\Transformer\Waveaccounting;
use App\Import\ImportException;
use App\Import\Transformer\BaseTransformer;
use App\Models\Invoice;
/**
* Class InvoiceTransformer.
*/
class InvoiceTransformer extends BaseTransformer {
/**
* @param $line_items_data
*
* @return bool|array
*/
public function transform( $line_items_data ) {
$invoice_data = reset( $line_items_data );
if ( $this->hasInvoice( $invoice_data['Invoice Number'] ) ) {
throw new ImportException( 'Invoice number already exists' );
}
$transformed = [
'company_id' => $this->company->id,
'client_id' => $this->getClient( $customer_name = $this->getString( $invoice_data, 'Customer' ), null ),
'number' => $invoice_number = $this->getString( $invoice_data, 'Invoice Number' ),
'date' => date( 'Y-m-d', strtotime( $invoice_data['Transaction Date'] ) ) ?: now()->format('Y-m-d'), //27-01-2022
'currency_id' => $this->getCurrencyByCode( $invoice_data, 'Currency' ),
'status_id' => Invoice::STATUS_SENT,
];
$line_items = [];
$payments = [];
foreach ( $line_items_data as $record ) {
if ( $record['Account Type'] === 'Income' ) {
$description = $this->getString( $record, 'Transaction Line Description' );
// Remove duplicate data from description
if ( substr( $description, 0, strlen( $customer_name ) + 3 ) === $customer_name . ' - ' ) {
$description = substr( $description, strlen( $customer_name ) + 3 );
}
if ( substr( $description, 0, strlen( $invoice_number ) + 3 ) === $invoice_number . ' - ' ) {
$description = substr( $description, strlen( $invoice_number ) + 3 );
}
$line_items[] = [
'notes' => $description,
'cost' => $this->getFloat( $record, 'Amount Before Sales Tax' ),
'tax_name1' => $this->getString( $record, 'Sales Tax Name' ),
'tax_rate1' => $this->getFloat( $record, 'Sales Tax Amount' ),
'quantity' => 1,
];
} elseif ( $record['Account Type'] === 'System Receivable Invoice' ) {
// This is a payment
$payments[] = [
'date' => date( 'Y-m-d', strtotime( $invoice_data['Transaction Date'] ) ),
'amount' => $this->getFloat( $record, 'Amount (One column)' ),
];
}
}
$transformed['line_items'] = $line_items;
$transformed['payments'] = $payments;
return $transformed;
}
}

View File

@ -0,0 +1,334 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace Tests\Feature\Import\CSV;
use App\Import\Providers\Wave;
use App\Import\Transformer\BaseTransformer;
use App\Utils\Traits\MakesHash;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Routing\Middleware\ThrottleRequests;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Str;
use Tests\MockAccountData;
use Tests\TestCase;
/**
* @test
* @covers App\Import\Providers\Wave
*/
class WaveTest extends TestCase
{
use MakesHash;
use MockAccountData;
use DatabaseTransactions;
public function setUp(): void
{
parent::setUp();
$this->withoutMiddleware(ThrottleRequests::class);
config(['database.default' => config('ninja.db.default')]);
$this->makeTestData();
$this->withoutExceptionHandling();
}
public function testClientWaveImport()
{
$csv = file_get_contents(
base_path() . '/tests/Feature/Import/wave_clients.csv'
);
$hash = Str::random(32);
$column_map = [
0 => 'client.name',
1 => 'contact.email',
2 => 'contact.first_name',
3 => 'contact.last_name',
4 => 'client.currency_id',
6 => 'client.phone',
10 => 'client.website',
11 => 'client.country_id',
12 => 'client.state',
13 => 'client.address1',
14 => 'client.address2',
15 => 'client.city',
16 => 'client.postal_code',
19 => 'client.shipping_country_id',
20 => 'client.shipping_state',
21 => 'client.shipping_address1',
22 => 'client.shipping_address2',
23 => 'client.shipping_city',
];
$data = [
'hash' => $hash,
'column_map' => ['client' => ['mapping' => $column_map]],
'skip_header' => true,
'import_type' => 'wave',
];
Cache::put($hash . '-client', base64_encode($csv), 360);
$csv_importer = new Wave($data, $this->company);
$count = $csv_importer->import('client');
$base_transformer = new BaseTransformer($this->company);
$this->assertTrue($base_transformer->hasClient('Homer Simpson'));
// $this->assertTrue($base_transformer->hasClient('Jessica Jones'));
// $this->assertTrue($base_transformer->hasClient('Lucas Cage'));
// $this->assertTrue($base_transformer->hasClient('Mark Walberg'));
}
// public function testVendorCsvImport()
// {
// $csv = file_get_contents(
// base_path() . '/tests/Feature/Import/vendors.csv'
// );
// $hash = Str::random(32);
// $column_map = [
// 0 => 'vendor.name',
// 19 => 'vendor.currency_id',
// 20 => 'vendor.public_notes',
// 21 => 'vendor.private_notes',
// 22 => 'vendor.first_name',
// 23 => 'vendor.last_name',
// ];
// $data = [
// 'hash' => $hash,
// 'column_map' => ['vendor' => ['mapping' => $column_map]],
// 'skip_header' => true,
// 'import_type' => 'csv',
// ];
// $pre_import = Vendor::count();
// Cache::put($hash . '-vendor', base64_encode($csv), 360);
// $csv_importer = new Csv($data, $this->company);
// $csv_importer->import('vendor');
// $base_transformer = new BaseTransformer($this->company);
// $this->assertTrue($base_transformer->hasVendor('Ludwig Krajcik DVM'));
// }
// public function testProductImport()
// {
// $csv = file_get_contents(
// base_path() . '/tests/Feature/Import/products.csv'
// );
// $hash = Str::random(32);
// Cache::put($hash . '-product', base64_encode($csv), 360);
// $column_map = [
// 1 => 'product.product_key',
// 2 => 'product.notes',
// 3 => 'product.cost',
// ];
// $data = [
// 'hash' => $hash,
// 'column_map' => ['product' => ['mapping' => $column_map]],
// 'skip_header' => true,
// 'import_type' => 'csv',
// ];
// $csv_importer = new Csv($data, $this->company);
// $this->assertInstanceOf(Csv::class, $csv_importer);
// $csv_importer->import('product');
// $base_transformer = new BaseTransformer($this->company);
// $this->assertTrue($base_transformer->hasProduct('officiis'));
// // $this->assertTrue($base_transformer->hasProduct('maxime'));
// }
// public function testClientImport()
// {
// $csv = file_get_contents(
// base_path() . '/tests/Feature/Import/clients.csv'
// );
// $hash = Str::random(32);
// $column_map = [
// 1 => 'client.balance',
// 2 => 'client.paid_to_date',
// 0 => 'client.name',
// 19 => 'client.currency_id',
// 20 => 'client.public_notes',
// 21 => 'client.private_notes',
// 22 => 'contact.first_name',
// 23 => 'contact.last_name',
// 24 => 'contact.email',
// ];
// $data = [
// 'hash' => $hash,
// 'column_map' => ['client' => ['mapping' => $column_map]],
// 'skip_header' => true,
// 'import_type' => 'csv',
// ];
// Cache::put($hash . '-client', base64_encode($csv), 360);
// $csv_importer = new Csv($data, $this->company);
// $this->assertInstanceOf(Csv::class, $csv_importer);
// $csv_importer->import('client');
// $base_transformer = new BaseTransformer($this->company);
// $this->assertTrue($base_transformer->hasClient('Ludwig Krajcik DVM'));
// $client_id = $base_transformer->getClient('Ludwig Krajcik DVM', null);
// $c = Client::find($client_id);
// $this->assertEquals($client_id, $c->id);
// $client_id = $base_transformer->getClient(
// 'a non existent clent',
// 'brook59@example.org'
// );
// $this->assertEquals($client_id, $c->id);
// }
// public function testInvoiceImport()
// {
// /*Need to import clients first*/
// $csv = file_get_contents(
// base_path() . '/tests/Feature/Import/clients.csv'
// );
// $hash = Str::random(32);
// $column_map = [
// 1 => 'client.balance',
// 2 => 'client.paid_to_date',
// 0 => 'client.name',
// 19 => 'client.currency_id',
// 20 => 'client.public_notes',
// 21 => 'client.private_notes',
// 22 => 'contact.first_name',
// 23 => 'contact.last_name',
// ];
// $data = [
// 'hash' => $hash,
// 'column_map' => ['client' => ['mapping' => $column_map]],
// 'skip_header' => true,
// 'import_type' => 'csv',
// ];
// Cache::put($hash . '-client', base64_encode($csv), 360);
// $csv_importer = new Csv($data, $this->company);
// $this->assertInstanceOf(Csv::class, $csv_importer);
// $csv_importer->import('client');
// $base_transformer = new BaseTransformer($this->company);
// $this->assertTrue($base_transformer->hasClient('Ludwig Krajcik DVM'));
// /* client import verified*/
// /*Now import invoices*/
// $csv = file_get_contents(
// base_path() . '/tests/Feature/Import/invoice.csv'
// );
// $hash = Str::random(32);
// $column_map = [
// 1 => 'client.email',
// 3 => 'payment.amount',
// 5 => 'invoice.po_number',
// 8 => 'invoice.due_date',
// 9 => 'item.discount',
// 11 => 'invoice.partial_due_date',
// 12 => 'invoice.public_notes',
// 13 => 'invoice.private_notes',
// 0 => 'client.name',
// 2 => 'invoice.number',
// 7 => 'invoice.date',
// 14 => 'item.product_key',
// 15 => 'item.notes',
// 16 => 'item.cost',
// 17 => 'item.quantity',
// ];
// $data = [
// 'hash' => $hash,
// 'column_map' => ['invoice' => ['mapping' => $column_map]],
// 'skip_header' => true,
// 'import_type' => 'csv',
// ];
// Cache::put($hash . '-invoice', base64_encode($csv), 360);
// $csv_importer = new Csv($data, $this->company);
// $csv_importer->import('invoice');
// $this->assertTrue($base_transformer->hasInvoice('801'));
// /* Lets piggy back payments tests here to save rebuilding the test multiple times*/
// $csv = file_get_contents(
// base_path() . '/tests/Feature/Import/payments.csv'
// );
// $hash = Str::random(32);
// $column_map = [
// 0 => 'payment.client_id',
// 1 => 'payment.invoice_number',
// 2 => 'payment.amount',
// 3 => 'payment.date',
// ];
// $data = [
// 'hash' => $hash,
// 'column_map' => ['payment' => ['mapping' => $column_map]],
// 'skip_header' => true,
// 'import_type' => 'csv',
// ];
// Cache::put($hash . '-payment', base64_encode($csv), 360);
// $csv_importer = new Csv($data, $this->company);
// $csv_importer->import('payment');
// $this->assertTrue($base_transformer->hasInvoice('801'));
// $invoice_id = $base_transformer->getInvoiceId('801');
// $invoice = Invoice::find($invoice_id);
// $this->assertTrue($invoice->payments()->exists());
// $this->assertEquals(1, $invoice->payments()->count());
// $this->assertEquals(400, $invoice->payments()->sum('payments.amount'));
// }
}