mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2024-11-10 13:12:50 +01:00
Merge pull request #7175 from turbo124/v5-develop
Fixes for blank currency_id in manually created payments
This commit is contained in:
commit
5227351485
@ -10,10 +10,17 @@
|
||||
*/
|
||||
namespace App\Import\Providers;
|
||||
|
||||
use App\Factory\ClientFactory;
|
||||
use App\Factory\InvoiceFactory;
|
||||
use App\Factory\PaymentFactory;
|
||||
use App\Http\Requests\Invoice\StoreInvoiceRequest;
|
||||
use App\Import\ImportException;
|
||||
use App\Models\Company;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\User;
|
||||
use App\Repositories\ClientRepository;
|
||||
use App\Repositories\InvoiceRepository;
|
||||
use App\Repositories\PaymentRepository;
|
||||
use App\Utils\Traits\CleanLineItems;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
@ -161,7 +168,7 @@ class BaseImport {
|
||||
}
|
||||
}
|
||||
|
||||
public function ingestInvoices( $invoices ) {
|
||||
public function ingestInvoices( $invoices , $invoice_number_key) {
|
||||
$invoice_transformer = $this->transformer;
|
||||
|
||||
/** @var PaymentRepository $payment_repository */
|
||||
@ -175,13 +182,14 @@ class BaseImport {
|
||||
$invoice_repository = new InvoiceRepository();
|
||||
$invoice_repository->import_mode = true;
|
||||
|
||||
$invoices = $this->groupInvoices($invoices, $invoice_number_key);
|
||||
|
||||
foreach ( $invoices as $raw_invoice ) {
|
||||
try {
|
||||
|
||||
$invoice_data = $invoice_transformer->transform( $raw_invoice );
|
||||
|
||||
$invoice_data['line_items'] = $this->cleanItems( $invoice_data['line_items'] ?? [] );
|
||||
|
||||
|
||||
// If we don't have a client ID, but we do have client data, go ahead and create the client.
|
||||
if ( empty( $invoice_data['client_id'] ) && ! empty( $invoice_data['client'] ) ) {
|
||||
$client_data = $invoice_data['client'];
|
||||
@ -205,7 +213,6 @@ class BaseImport {
|
||||
$invoice->status_id = $invoice_data['status_id'];
|
||||
}
|
||||
$invoice_repository->save( $invoice_data, $invoice );
|
||||
$this->addInvoiceToMaps( $invoice );
|
||||
|
||||
// If we're doing a generic CSV import, only import payment data if we're not importing a payment CSV.
|
||||
// If we're doing a platform-specific import, trust the platform to only return payment info if there's not a separate payment CSV.
|
||||
@ -273,13 +280,36 @@ class BaseImport {
|
||||
|
||||
|
||||
|
||||
private function actionInvoiceStatus( $invoice, $invoice_data, $invoice_repository ) {
|
||||
if ( ! empty( $invoice_data['archived'] ) ) {
|
||||
$invoice_repository->archive( $invoice );
|
||||
$invoice->fresh();
|
||||
}
|
||||
|
||||
if ( ! empty( $invoice_data['viewed'] ) ) {
|
||||
$invoice = $invoice->service()->markViewed()->save();
|
||||
}
|
||||
|
||||
if( $invoice->status_id === Invoice::STATUS_DRAFT ){
|
||||
|
||||
}
|
||||
elseif ( $invoice->status_id === Invoice::STATUS_SENT ) {
|
||||
$invoice = $invoice->service()->markSent()->save();
|
||||
}
|
||||
elseif ( $invoice->status_id <= Invoice::STATUS_SENT && $invoice->amount > 0 ) {
|
||||
if ( $invoice->balance <= 0 ) {
|
||||
$invoice->status_id = Invoice::STATUS_PAID;
|
||||
$invoice->save();
|
||||
}
|
||||
elseif ( $invoice->balance != $invoice->amount ) {
|
||||
$invoice->status_id = Invoice::STATUS_PARTIAL;
|
||||
$invoice->save();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
return $invoice;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -20,6 +20,7 @@ use App\Import\ImportException;
|
||||
use App\Import\Providers\BaseImport;
|
||||
use App\Import\Providers\ImportInterface;
|
||||
use App\Import\Transformer\Csv\ClientTransformer;
|
||||
use App\Import\Transformer\Csv\InvoiceTransformer;
|
||||
use App\Import\Transformer\Csv\ProductTransformer;
|
||||
use App\Repositories\ClientRepository;
|
||||
use App\Repositories\InvoiceRepository;
|
||||
@ -123,9 +124,9 @@ class Csv extends BaseImport implements ImportInterface
|
||||
$this->repository = app()->make( $this->repository_name );
|
||||
$this->repository->import_mode = true;
|
||||
|
||||
$this->transformer = new ProductTransformer($this->company);
|
||||
$this->transformer = new InvoiceTransformer($this->company);
|
||||
|
||||
$invoice_count = $this->ingest($data, $entity_type);
|
||||
$invoice_count = $this->ingestInvoices($data, 'invoice.number');
|
||||
|
||||
$this->entity_count['invoices'] = $invoice_count;
|
||||
|
||||
|
@ -53,20 +53,23 @@ class BaseTransformer
|
||||
|
||||
}
|
||||
|
||||
public function getClient($client_name, $client_email) {
|
||||
public function getClient($client_name, $client_email)
|
||||
{
|
||||
|
||||
// nlog("searching for {$client_name} with email {$client_email}");
|
||||
|
||||
$client_id_search = $this->company->clients()->where( 'id_number', $client_name );
|
||||
|
||||
if ( $client_id_search->count() >= 1 ) {
|
||||
// nlog("found via id number => {$client_id_search->first()->id}");
|
||||
return $client_id_search->first()->id;
|
||||
nlog("found via id number");
|
||||
}
|
||||
|
||||
$client_name_search = $this->company->clients()->where( 'name', $client_name );
|
||||
|
||||
if ( $client_name_search->count() >= 1 ) {
|
||||
// nlog("found via name {$client_name_search->first()->id}");
|
||||
return $client_name_search->first()->id;
|
||||
nlog("found via name");
|
||||
}
|
||||
|
||||
if ( ! empty( $client_email ) ) {
|
||||
@ -74,11 +77,12 @@ class BaseTransformer
|
||||
->where( 'email', $client_email );
|
||||
|
||||
if ( $contacts->count() >= 1 ) {
|
||||
// nlog("found via contact {$contacts->first()->client_id}");
|
||||
return $contacts->first()->client_id;
|
||||
nlog("found via contact");
|
||||
}
|
||||
}
|
||||
nlog("did not find client");
|
||||
|
||||
// nlog("did not find client");
|
||||
|
||||
return null;
|
||||
}
|
||||
|
@ -13,18 +13,22 @@ namespace App\Import\Transformer\Csv;
|
||||
|
||||
use App\Import\ImportException;
|
||||
use App\Import\Transformer\BaseTransformer;
|
||||
use App\Import\Transformer\Csv\ClientTransformer;
|
||||
use App\Models\Invoice;
|
||||
|
||||
/**
|
||||
* Class InvoiceTransformer.
|
||||
*/
|
||||
class InvoiceTransformer extends BaseTransformer {
|
||||
|
||||
|
||||
/**
|
||||
* @param $data
|
||||
*
|
||||
* @return bool|array
|
||||
*/
|
||||
public function transform( $line_items_data ) {
|
||||
|
||||
$invoice_data = reset( $line_items_data );
|
||||
|
||||
if ( $this->hasInvoice( $invoice_data['invoice.number'] ) ) {
|
||||
@ -74,6 +78,16 @@ class InvoiceTransformer extends BaseTransformer {
|
||||
'archived' => $status === 'archived',
|
||||
];
|
||||
|
||||
/* If we can't find the client, then lets try and create a client */
|
||||
if(!$transformed['client_id']){
|
||||
|
||||
$client_transformer = new ClientTransformer($this->company);
|
||||
|
||||
$transformed['client'] = $client_transformer->transform($invoice_data);
|
||||
|
||||
}
|
||||
|
||||
|
||||
if ( isset( $invoice_data['payment.amount'] ) ) {
|
||||
$transformed['payments'] = [
|
||||
[
|
||||
@ -119,7 +133,7 @@ class InvoiceTransformer extends BaseTransformer {
|
||||
'custom_value2' => $this->getString( $record, 'item.custom_value2' ),
|
||||
'custom_value3' => $this->getString( $record, 'item.custom_value3' ),
|
||||
'custom_value4' => $this->getString( $record, 'item.custom_value4' ),
|
||||
'type_id' => $this->getInvoiceTypeId( $record, 'item.type_id' ),
|
||||
'type_id' => "1", //$this->getInvoiceTypeId( $record, 'item.type_id' ),
|
||||
];
|
||||
}
|
||||
$transformed['line_items'] = $line_items;
|
||||
|
64
app/Import/Transformer/Csv/PaymentTransformer.php
Normal file
64
app/Import/Transformer/Csv/PaymentTransformer.php
Normal file
@ -0,0 +1,64 @@
|
||||
<?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\Csv;
|
||||
|
||||
use App\Import\ImportException;
|
||||
use App\Import\Transformer\BaseTransformer;
|
||||
|
||||
/**
|
||||
* Class PaymentTransformer.
|
||||
*/
|
||||
class PaymentTransformer extends BaseTransformer {
|
||||
/**
|
||||
* @param $data
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function transform( $data ) {
|
||||
|
||||
$client_id = $this->getClient( $this->getString( $data, 'payment.client_id' ), $this->getString( $data, 'payment.client_id' ) );
|
||||
|
||||
if ( empty( $client_id ) ) {
|
||||
throw new ImportException( 'Could not find client.' );
|
||||
}
|
||||
|
||||
$transformed = [
|
||||
'company_id' => $this->maps['company']->id,
|
||||
'number' => $this->getString( $data, 'payment.number' ),
|
||||
'user_id' => $this->getString( $data, 'payment.user_id' ),
|
||||
'amount' => $this->getFloat( $data, 'payment.amount' ),
|
||||
'refunded' => $this->getFloat( $data, 'payment.refunded' ),
|
||||
'applied' => $this->getFloat( $data, 'payment.applied' ),
|
||||
'transaction_reference' => $this->getString( $data, 'payment.transaction_reference ' ),
|
||||
'date' => $this->getString( $data, 'payment.date' ),
|
||||
'private_notes' => $this->getString( $data, 'payment.private_notes' ),
|
||||
'custom_value1' => $this->getString( $data, 'payment.custom_value1' ),
|
||||
'custom_value2' => $this->getString( $data, 'payment.custom_value2' ),
|
||||
'custom_value3' => $this->getString( $data, 'payment.custom_value3' ),
|
||||
'custom_value4' => $this->getString( $data, 'payment.custom_value4' ),
|
||||
'client_id' => $client_id,
|
||||
];
|
||||
|
||||
|
||||
if ( isset( $data['payment.invoice_number'] ) &&
|
||||
$invoice_id = $this->getInvoiceId( $data['payment.invoice_number'] ) ) {
|
||||
$transformed['invoices'] = [
|
||||
[
|
||||
'invoice_id' => $invoice_id,
|
||||
'amount' => $transformed['amount'] ?? null,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
return $transformed;
|
||||
}
|
||||
}
|
@ -58,11 +58,16 @@ class CreditCard
|
||||
|
||||
public function paymentView(array $data)
|
||||
{
|
||||
|
||||
|
||||
$description = $this->stripe->decodeUnicodeString(ctrans('texts.invoices') . ': ' . collect($data['invoices'])->pluck('invoice_number')) . " for client {$this->stripe->client->present()->name()}";
|
||||
|
||||
|
||||
$payment_intent_data = [
|
||||
'amount' => $this->stripe->convertToStripeAmount($data['total']['amount_with_fee'], $this->stripe->client->currency()->precision, $this->stripe->client->currency()),
|
||||
'currency' => $this->stripe->client->getCurrencyCode(),
|
||||
'customer' => $this->stripe->findOrCreateCustomer(),
|
||||
'description' => $this->stripe->decodeUnicodeString(ctrans('texts.invoices') . ': ' . collect($data['invoices'])->pluck('invoice_number')),
|
||||
'description' => $description,
|
||||
'metadata' => [
|
||||
'payment_hash' => $this->stripe->payment_hash->hash,
|
||||
'gateway_type_id' => GatewayType::CREDIT_CARD,
|
||||
|
@ -211,6 +211,9 @@ class PaymentRepository extends BaseRepository {
|
||||
$payment->currency_id = $client_currency;
|
||||
|
||||
}
|
||||
|
||||
$payment->currency_id = $company_currency;
|
||||
|
||||
|
||||
return $payment;
|
||||
}
|
||||
|
@ -54,7 +54,39 @@ class CsvImportTest extends TestCase
|
||||
$this->withoutExceptionHandling();
|
||||
}
|
||||
|
||||
public function testCsvFeature()
|
||||
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);
|
||||
@ -101,6 +133,95 @@ class CsvImportTest extends TestCase
|
||||
|
||||
}
|
||||
|
||||
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"));
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user