mirror of
				https://github.com/invoiceninja/invoiceninja.git
				synced 2025-11-04 06:37:33 -05:00 
			
		
		
		
	Merge pull request #6593 from turbo124/v5-develop
Add withTrashed() when searching for MultiDB users
This commit is contained in:
		
						commit
						c9ea2ceaf3
					
				@ -67,18 +67,6 @@ class InvoiceFilters extends QueryFilters
 | 
			
		||||
        return $this->builder;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function client_id(string $client_id = '') :Builder
 | 
			
		||||
    {
 | 
			
		||||
        if (strlen($client_id) == 0) {
 | 
			
		||||
            return $this->builder;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $this->builder->where('client_id', $this->decodePrimaryKey($client_id));
 | 
			
		||||
 | 
			
		||||
        return $this->builder;
 | 
			
		||||
        
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function number(string $number) :Builder
 | 
			
		||||
    {
 | 
			
		||||
        return $this->builder->where('number', $number);
 | 
			
		||||
 | 
			
		||||
@ -12,6 +12,7 @@
 | 
			
		||||
namespace App\Filters;
 | 
			
		||||
 | 
			
		||||
//use Illuminate\Database\Query\Builder;
 | 
			
		||||
use App\Utils\Traits\MakesHash;
 | 
			
		||||
use Illuminate\Database\Eloquent\Builder;
 | 
			
		||||
use Illuminate\Http\Request;
 | 
			
		||||
 | 
			
		||||
@ -20,6 +21,8 @@ use Illuminate\Http\Request;
 | 
			
		||||
 */
 | 
			
		||||
abstract class QueryFilters
 | 
			
		||||
{
 | 
			
		||||
    use MakesHash;
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * active status.
 | 
			
		||||
     */
 | 
			
		||||
@ -177,6 +180,18 @@ abstract class QueryFilters
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function client_id(string $client_id = '') :Builder
 | 
			
		||||
    {
 | 
			
		||||
        if (strlen($client_id) == 0) {
 | 
			
		||||
            return $this->builder;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $this->builder->where('client_id', $this->decodePrimaryKey($client_id));
 | 
			
		||||
 | 
			
		||||
        return $this->builder;
 | 
			
		||||
        
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function filter_deleted_clients($value)
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -34,11 +34,6 @@ class SystemLogFilters extends QueryFilters
 | 
			
		||||
        return $this->builder->where('event_id', $event_id);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function client_id(int $client_id) :Builder
 | 
			
		||||
    {
 | 
			
		||||
        return $this->builder->where('client_id', $client_id);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Filter based on search text.
 | 
			
		||||
     *
 | 
			
		||||
 | 
			
		||||
@ -30,7 +30,7 @@ class InvoiceSum
 | 
			
		||||
 | 
			
		||||
    public $invoice_item;
 | 
			
		||||
 | 
			
		||||
    public $total_taxes;
 | 
			
		||||
    public $total_taxes = 0;
 | 
			
		||||
 | 
			
		||||
    private $total;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -20,7 +20,9 @@ use App\Utils\Number;
 | 
			
		||||
use App\Utils\TempFile;
 | 
			
		||||
use App\Utils\Traits\MakesDates;
 | 
			
		||||
use App\Utils\Traits\MakesHash;
 | 
			
		||||
use Illuminate\Contracts\Container\BindingResolutionException;
 | 
			
		||||
use Illuminate\Contracts\View\Factory;
 | 
			
		||||
use Illuminate\Http\RedirectResponse;
 | 
			
		||||
use Illuminate\View\View;
 | 
			
		||||
use ZipStream\Option\Archive;
 | 
			
		||||
use ZipStream\ZipStream;
 | 
			
		||||
@ -86,6 +88,10 @@ class InvoiceController extends Controller
 | 
			
		||||
            ->with('message', ctrans('texts.no_action_provided'));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @param array $ids 
 | 
			
		||||
     * @return Factory|View|RedirectResponse 
 | 
			
		||||
     */
 | 
			
		||||
    private function makePayment(array $ids)
 | 
			
		||||
    {
 | 
			
		||||
        $invoices = Invoice::whereIn('id', $ids)
 | 
			
		||||
@ -119,8 +125,8 @@ class InvoiceController extends Controller
 | 
			
		||||
        //format data
 | 
			
		||||
        $invoices->map(function ($invoice) {
 | 
			
		||||
            $invoice->service()->removeUnpaidGatewayFees()->save();
 | 
			
		||||
            $invoice->balance = Number::formatValue($invoice->balance, $invoice->client->currency());
 | 
			
		||||
            $invoice->partial = Number::formatValue($invoice->partial, $invoice->client->currency());
 | 
			
		||||
            $invoice->balance = $invoice->balance > 0 ? Number::formatValue($invoice->balance, $invoice->client->currency()) : 0;
 | 
			
		||||
            $invoice->partial =  $invoice->partial > 0 ? Number::formatValue($invoice->partial, $invoice->client->currency()) : 0;
 | 
			
		||||
 | 
			
		||||
            return $invoice;
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
@ -60,6 +60,8 @@ class StoreUserRequest extends Request
 | 
			
		||||
 | 
			
		||||
//unique user rule - check company_user table for user_id / company_id  / account_id if none exist we can add the user. ELSE return false
 | 
			
		||||
 | 
			
		||||
        if(array_key_exists('email', $input))
 | 
			
		||||
            $input['email'] = trim($input['email']);
 | 
			
		||||
 | 
			
		||||
        if (isset($input['company_user'])) {
 | 
			
		||||
            if (! isset($input['company_user']['is_admin'])) {
 | 
			
		||||
 | 
			
		||||
@ -45,6 +45,8 @@ class UpdateUserRequest extends Request
 | 
			
		||||
    {
 | 
			
		||||
        $input = $this->all();
 | 
			
		||||
 | 
			
		||||
        if(array_key_exists('email', $input))
 | 
			
		||||
            $input['email'] = trim($input['email']);
 | 
			
		||||
 | 
			
		||||
        $this->replace($input);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -62,7 +62,7 @@ class BaseTransformer
 | 
			
		||||
    public function getClient($client_name, $client_email) {
 | 
			
		||||
		$clients = $this->maps['company']->clients;
 | 
			
		||||
 | 
			
		||||
		$clients = $clients->where( 'name', $client_name );
 | 
			
		||||
		$clients = $clients->where( 'id_number', $client_name );
 | 
			
		||||
 | 
			
		||||
		if ( $clients->count() >= 1 ) {
 | 
			
		||||
			return $clients->first()->id;
 | 
			
		||||
 | 
			
		||||
@ -42,7 +42,7 @@ class ClientTransformer extends BaseTransformer {
 | 
			
		||||
			'work_phone'    => $this->getString( $data, 'Phone' ),
 | 
			
		||||
			'private_notes' => $this->getString( $data, 'Notes' ),
 | 
			
		||||
			'website'       => $this->getString( $data, 'Website' ),
 | 
			
		||||
 | 
			
		||||
			'id_number'		=> $this->getString( $data, 'Customer ID'),
 | 
			
		||||
			'address1'    => $this->getString( $data, 'Billing Address' ),
 | 
			
		||||
			'address2'    => $this->getString( $data, 'Billing Street2' ),
 | 
			
		||||
			'city'        => $this->getString( $data, 'Billing City' ),
 | 
			
		||||
 | 
			
		||||
@ -38,7 +38,7 @@ class InvoiceTransformer extends BaseTransformer {
 | 
			
		||||
 | 
			
		||||
		$transformed = [
 | 
			
		||||
			'company_id'   => $this->maps['company']->id,
 | 
			
		||||
			'client_id'    => $this->getClient( $this->getString( $invoice_data, 'Company Name' ), null ),
 | 
			
		||||
			'client_id'    => $this->getClient( $this->getString( $invoice_data, 'Customer ID' ), null ),
 | 
			
		||||
			'number'       => $this->getString( $invoice_data, 'Invoice Number' ),
 | 
			
		||||
			'date'         => isset( $invoice_data['Invoice Date'] ) ? date( 'Y-m-d', strtotime( $invoice_data['Invoice Date'] ) ) : null,
 | 
			
		||||
			'due_date'     => isset( $invoice_data['Due Date'] ) ? date( 'Y-m-d', strtotime( $invoice_data['Due Date'] ) ) : null,
 | 
			
		||||
@ -59,7 +59,7 @@ class InvoiceTransformer extends BaseTransformer {
 | 
			
		||||
				'notes'              => $this->getString( $record, 'Item Description' ),
 | 
			
		||||
				'cost'               => $this->getFloat( $record, 'Item Price' ),
 | 
			
		||||
				'quantity'           => $this->getFloat( $record, 'Quantity' ),
 | 
			
		||||
				'discount'           => $this->getFloat( $record, 'Discount Amount' ),
 | 
			
		||||
				'discount'           => $this->getString( $record, 'Discount Amount' ),
 | 
			
		||||
				'is_amount_discount' => true,
 | 
			
		||||
			];
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
@ -56,8 +56,8 @@ class AutoBillCron
 | 
			
		||||
 | 
			
		||||
                                        nlog($auto_bill_partial_invoices->count(). " partial invoices to auto bill");
 | 
			
		||||
 | 
			
		||||
                                        $auto_bill_partial_invoices->cursor()->each(function ($invoice) use($db){
 | 
			
		||||
                                            $this->runAutoBiller($invoice, $db);
 | 
			
		||||
                                        $auto_bill_partial_invoices->cursor()->each(function ($invoice){
 | 
			
		||||
                                            $this->runAutoBiller($invoice, false);
 | 
			
		||||
                                        });
 | 
			
		||||
 | 
			
		||||
            $auto_bill_invoices = Invoice::whereDate('due_date', '<=', now())
 | 
			
		||||
@ -69,8 +69,8 @@ class AutoBillCron
 | 
			
		||||
 | 
			
		||||
                                        nlog($auto_bill_invoices->count(). " full invoices to auto bill");
 | 
			
		||||
                                        
 | 
			
		||||
                                        $auto_bill_invoices->cursor()->each(function ($invoice) use($db){
 | 
			
		||||
                                            $this->runAutoBiller($invoice, $db);
 | 
			
		||||
                                        $auto_bill_invoices->cursor()->each(function ($invoice){
 | 
			
		||||
                                            $this->runAutoBiller($invoice, false);
 | 
			
		||||
                                        });
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -115,8 +115,12 @@ class AutoBillCron
 | 
			
		||||
        info("Firing autobill for {$invoice->company_id} - {$invoice->number}");
 | 
			
		||||
 | 
			
		||||
        try{
 | 
			
		||||
 | 
			
		||||
            if($db)
 | 
			
		||||
                MultiDB::setDB($db);
 | 
			
		||||
                
 | 
			
		||||
            $invoice->service()->autoBill()->save();
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
        catch(\Exception $e) {
 | 
			
		||||
            nlog("Failed to capture payment for {$invoice->company_id} - {$invoice->number} ->" . $e->getMessage());
 | 
			
		||||
 | 
			
		||||
@ -30,6 +30,7 @@ use App\Providers\MailServiceProvider;
 | 
			
		||||
use App\Utils\Ninja;
 | 
			
		||||
use App\Utils\Traits\MakesHash;
 | 
			
		||||
use Dacastro4\LaravelGmail\Facade\LaravelGmail;
 | 
			
		||||
use GuzzleHttp\Exception\ClientException;
 | 
			
		||||
use Illuminate\Bus\Queueable;
 | 
			
		||||
use Illuminate\Contracts\Queue\ShouldQueue;
 | 
			
		||||
use Illuminate\Foundation\Bus\Dispatchable;
 | 
			
		||||
@ -118,10 +119,18 @@ class NinjaMailerJob implements ShouldQueue
 | 
			
		||||
            
 | 
			
		||||
            nlog("error failed with {$e->getMessage()}");
 | 
			
		||||
 | 
			
		||||
            if($this->nmo->entity)
 | 
			
		||||
                $this->entityEmailFailed($e->getMessage());
 | 
			
		||||
            $message = $e->getMessage();
 | 
			
		||||
 | 
			
		||||
            if(Ninja::isHosted())
 | 
			
		||||
            if($e instanceof ClientException) { //postmark specific failure
 | 
			
		||||
 | 
			
		||||
                $response = $e->getResponse();
 | 
			
		||||
                $message = $response->Message;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if($this->nmo->entity)
 | 
			
		||||
                $this->entityEmailFailed($message);
 | 
			
		||||
 | 
			
		||||
            if(Ninja::isHosted() && (!$e instanceof ClientException)) // Don't send postmark failures to Sentry
 | 
			
		||||
                app('sentry')->captureException($e);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@ -241,6 +250,7 @@ class NinjaMailerJob implements ShouldQueue
 | 
			
		||||
 | 
			
		||||
    private function logMailError($errors, $recipient_object)
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
        SystemLogger::dispatch(
 | 
			
		||||
            $errors,
 | 
			
		||||
            SystemLog::CATEGORY_MAIL,
 | 
			
		||||
@ -249,19 +259,18 @@ class NinjaMailerJob implements ShouldQueue
 | 
			
		||||
            $recipient_object,
 | 
			
		||||
            $this->nmo->company
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function failed($exception = null)
 | 
			
		||||
    {
 | 
			
		||||
        nlog('mailer job failed');
 | 
			
		||||
        nlog($exception->getMessage());
 | 
			
		||||
 | 
			
		||||
        $job_failure = new EmailFailure($this->nmo->company->company_key);
 | 
			
		||||
        $job_failure->string_metric5 = 'failed_email';
 | 
			
		||||
        $job_failure->string_metric6 = substr($exception->getMessage(), 0, 150);
 | 
			
		||||
        $job_failure->string_metric6 = substr($errors, 0, 150);
 | 
			
		||||
 | 
			
		||||
        LightLogs::create($job_failure)
 | 
			
		||||
                 ->batch();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function failed($exception = null)
 | 
			
		||||
    {
 | 
			
		||||
        
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -147,6 +147,8 @@ class SendRecurring implements ShouldQueue
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //important catch all here - we should never leave contacts send_email to false incase they are permanently set to false in the future.
 | 
			
		||||
        $this->recurring_invoice->client->contacts()->update(['send_email' => true]);
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -73,12 +73,12 @@ class MultiDB
 | 
			
		||||
    public static function checkUserEmailExists($email) : bool
 | 
			
		||||
    {
 | 
			
		||||
        if (! config('ninja.db.multi_db_enabled')) 
 | 
			
		||||
            return User::where(['email' => $email])->exists(); // true >= 1 emails found / false -> == emails found
 | 
			
		||||
            return User::where(['email' => $email])->withTrashed()->exists(); // true >= 1 emails found / false -> == emails found
 | 
			
		||||
        
 | 
			
		||||
        $current_db = config('database.default');  
 | 
			
		||||
 | 
			
		||||
        foreach (self::$dbs as $db) {
 | 
			
		||||
            if (User::on($db)->where(['email' => $email])->exists()) { // if user already exists, validation will fail
 | 
			
		||||
            if (User::on($db)->where(['email' => $email])->withTrashed()->exists()) { // if user already exists, validation will fail
 | 
			
		||||
                self::setDb($current_db);
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
@ -107,7 +107,7 @@ class MultiDB
 | 
			
		||||
        $current_db = config('database.default');  
 | 
			
		||||
 | 
			
		||||
        foreach (self::$dbs as $db) {
 | 
			
		||||
            if (User::on($db)->where(['email' => $email])->exists()) { 
 | 
			
		||||
            if (User::on($db)->where(['email' => $email])->withTrashed()->exists()) { 
 | 
			
		||||
                if (Company::on($db)->where(['company_key' => $company_key])->exists()) {
 | 
			
		||||
                    self::setDb($current_db);
 | 
			
		||||
                    return true;
 | 
			
		||||
@ -196,7 +196,7 @@ class MultiDB
 | 
			
		||||
        //multi-db active
 | 
			
		||||
        foreach (self::$dbs as $db) {
 | 
			
		||||
            
 | 
			
		||||
            if (User::on($db)->where('email', $email)->exists()){ 
 | 
			
		||||
            if (User::on($db)->where('email', $email)->withTrashed()->exists()){ 
 | 
			
		||||
                self::setDb($db);
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@ -478,7 +478,7 @@ class BaseDriver extends AbstractPaymentDriver
 | 
			
		||||
            $message,
 | 
			
		||||
            SystemLog::CATEGORY_GATEWAY_RESPONSE,
 | 
			
		||||
            SystemLog::EVENT_GATEWAY_FAILURE,
 | 
			
		||||
            $this::SYSTEM_LOG_TYPE,
 | 
			
		||||
            SystemLog::TYPE_PAYTRACE,
 | 
			
		||||
            $this->client,
 | 
			
		||||
            $this->client->company,
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
@ -28,6 +28,7 @@ class BaseRepository
 | 
			
		||||
{
 | 
			
		||||
    use MakesHash;
 | 
			
		||||
    use SavesDocuments;
 | 
			
		||||
 | 
			
		||||
	public $import_mode = false;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 | 
			
		||||
@ -71,6 +71,7 @@ class ClientContactRepository extends BaseRepository
 | 
			
		||||
                $client->company->client_contacts()->where('email', $update_contact->email)->update(['password' => $update_contact->password]);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            $update_contact->email = trim($contact['email']);
 | 
			
		||||
            $update_contact->save();
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -170,10 +170,10 @@ class PaymentRepository extends BaseRepository {
 | 
			
		||||
            event( new PaymentWasCreated( $payment, $payment->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null) ) );
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
        nlog("payment amount = {$payment->amount}");
 | 
			
		||||
        nlog("payment applied = {$payment->applied}");
 | 
			
		||||
        nlog("invoice totals = {$invoice_totals}");
 | 
			
		||||
        nlog("credit totals = {$credit_totals}");
 | 
			
		||||
        // nlog("payment amount = {$payment->amount}");
 | 
			
		||||
        // nlog("payment applied = {$payment->applied}");
 | 
			
		||||
        // nlog("invoice totals = {$invoice_totals}");
 | 
			
		||||
        // nlog("credit totals = {$credit_totals}");
 | 
			
		||||
 | 
			
		||||
        $payment->applied += ($invoice_totals - $credit_totals); //wont work because - check tests
 | 
			
		||||
        // $payment->applied += $invoice_totals; //wont work because - check tests
 | 
			
		||||
 | 
			
		||||
@ -84,6 +84,8 @@ class DeletePayment
 | 
			
		||||
                
 | 
			
		||||
                nlog("net deletable amount - refunded = {$net_deletable}");
 | 
			
		||||
                
 | 
			
		||||
                if(!$paymentable_invoice->is_deleted)
 | 
			
		||||
                {
 | 
			
		||||
                    $paymentable_invoice->service()
 | 
			
		||||
                                        ->updateBalance($net_deletable)
 | 
			
		||||
                                        ->updatePaidToDate($net_deletable * -1)
 | 
			
		||||
@ -104,6 +106,20 @@ class DeletePayment
 | 
			
		||||
                    } else {
 | 
			
		||||
                        $paymentable_invoice->service()->setStatus(Invoice::STATUS_PARTIAL)->save();
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                else {
 | 
			
		||||
 | 
			
		||||
                    //If the invoice is deleted we only update the meta data on the invoice
 | 
			
		||||
                    //and reduce the clients paid to date
 | 
			
		||||
                    $paymentable_invoice->service()
 | 
			
		||||
                                        ->updatePaidToDate($net_deletable * -1)
 | 
			
		||||
                                        ->save();
 | 
			
		||||
 | 
			
		||||
                    // $paymentable_invoice->client
 | 
			
		||||
                    // ->service()
 | 
			
		||||
                    // ->updatePaidToDate($net_deletable * -1)
 | 
			
		||||
                    // ->save();
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -271,6 +271,8 @@ trait MakesInvoiceValues
 | 
			
		||||
            $data;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        $locale_info = localeconv();
 | 
			
		||||
 | 
			
		||||
        foreach ($items as $key => $item) {
 | 
			
		||||
            if ($table_type == '$product' && $item->type_id != 1) {
 | 
			
		||||
                if ($item->type_id != 4 && $item->type_id != 6 && $item->type_id != 5) {
 | 
			
		||||
@ -301,8 +303,10 @@ trait MakesInvoiceValues
 | 
			
		||||
            $data[$key][$table_type . ".{$_table_type}3"] = $helpers->formatCustomFieldValue($this->client->company->custom_fields, "{$_table_type}3", $item->custom_value3, $this->client);
 | 
			
		||||
            $data[$key][$table_type . ".{$_table_type}4"] = $helpers->formatCustomFieldValue($this->client->company->custom_fields, "{$_table_type}4", $item->custom_value4, $this->client);
 | 
			
		||||
 | 
			
		||||
            $data[$key][$table_type.'.quantity'] = Number::formatValue($item->quantity, $this->client->currency());
 | 
			
		||||
            //$data[$key][$table_type.'.quantity'] = Number::formatValue($item->quantity, $this->client->currency());
 | 
			
		||||
            
 | 
			
		||||
            //change quantity from localized number, to decimal format with no trailing zeroes 06/09/21
 | 
			
		||||
            $data[$key][$table_type.'.quantity'] =  rtrim($item->quantity, $locale_info['decimal_point']);
 | 
			
		||||
            $data[$key][$table_type.'.unit_cost'] = Number::formatMoney($item->cost, $this->client);
 | 
			
		||||
            $data[$key][$table_type.'.cost'] = Number::formatMoney($item->cost, $this->client);
 | 
			
		||||
 | 
			
		||||
@ -483,7 +487,7 @@ trait MakesInvoiceValues
 | 
			
		||||
                    $output = (int)$raw - (int)$_value[1]; // 1 (:MONTH) - 4
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if ($_operation == '/') {
 | 
			
		||||
                if ($_operation == '/' && (int)$_value[1] != 0) {
 | 
			
		||||
                    $output = (int)$raw / (int)$_value[1]; // 1 (:MONTH) / 4
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										376
									
								
								tests/Feature/MultiPaymentDeleteTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										376
									
								
								tests/Feature/MultiPaymentDeleteTest.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,376 @@
 | 
			
		||||
<?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;
 | 
			
		||||
 | 
			
		||||
use App\Factory\CompanyTokenFactory;
 | 
			
		||||
use App\Factory\CompanyUserFactory;
 | 
			
		||||
use App\Factory\InvoiceFactory;
 | 
			
		||||
use App\Factory\InvoiceItemFactory;
 | 
			
		||||
use App\Models\Account;
 | 
			
		||||
use App\Models\Client;
 | 
			
		||||
use App\Models\ClientContact;
 | 
			
		||||
use App\Models\Company;
 | 
			
		||||
use App\Models\CompanyToken;
 | 
			
		||||
use App\Models\Invoice;
 | 
			
		||||
use App\Models\Payment;
 | 
			
		||||
use App\Models\User;
 | 
			
		||||
use App\Utils\Traits\MakesHash;
 | 
			
		||||
use Illuminate\Foundation\Testing\DatabaseTransactions;
 | 
			
		||||
use Illuminate\Validation\ValidationException;
 | 
			
		||||
use Tests\TestCase;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @test
 | 
			
		||||
 */
 | 
			
		||||
class MultiPaymentDeleteTest extends TestCase
 | 
			
		||||
{
 | 
			
		||||
    use DatabaseTransactions, MakesHash;
 | 
			
		||||
 | 
			
		||||
    private $faker;
 | 
			
		||||
 | 
			
		||||
    public function setUp() :void
 | 
			
		||||
    {
 | 
			
		||||
        parent::setUp();
 | 
			
		||||
 | 
			
		||||
        $this->faker = \Faker\Factory::create();
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testComplexRefundDeleteScenario()
 | 
			
		||||
    {
 | 
			
		||||
        $account = Account::factory()->create();
 | 
			
		||||
        $company = Company::factory()->create([
 | 
			
		||||
                    'account_id' => $account->id,
 | 
			
		||||
                ]);
 | 
			
		||||
 | 
			
		||||
        $account->default_company_id = $company->id;
 | 
			
		||||
        $account->save();
 | 
			
		||||
 | 
			
		||||
        $user = User::factory()->create([
 | 
			
		||||
            'account_id' => $account->id,
 | 
			
		||||
            'confirmation_code' => '11',
 | 
			
		||||
            'email' => $this->faker->unique()->safeEmail,
 | 
			
		||||
        ]);
 | 
			
		||||
 | 
			
		||||
        $cu = CompanyUserFactory::create($user->id, $company->id, $account->id);
 | 
			
		||||
        $cu->is_owner = true;
 | 
			
		||||
        $cu->is_admin = true;
 | 
			
		||||
        $cu->save();
 | 
			
		||||
 | 
			
		||||
        $token = new CompanyToken;
 | 
			
		||||
        $token->user_id = $user->id;
 | 
			
		||||
        $token->company_id = $company->id;
 | 
			
		||||
        $token->account_id = $account->id;
 | 
			
		||||
        $token->name = 'test token';
 | 
			
		||||
        $token->token = 'okeytokey';
 | 
			
		||||
        $token->is_system = true;
 | 
			
		||||
        $token->save();
 | 
			
		||||
 | 
			
		||||
        $client = Client::factory()->create([
 | 
			
		||||
            'user_id' => $user->id, 
 | 
			
		||||
            'company_id' => $company->id,
 | 
			
		||||
        ]);  
 | 
			
		||||
 | 
			
		||||
        ClientContact::factory()->create([
 | 
			
		||||
            'user_id' => $user->id,
 | 
			
		||||
            'client_id' => $client->id,
 | 
			
		||||
            'company_id' => $company->id,
 | 
			
		||||
            'is_primary' => 1,
 | 
			
		||||
        ]);
 | 
			
		||||
 | 
			
		||||
        ClientContact::factory()->create([
 | 
			
		||||
            'user_id' => $user->id,
 | 
			
		||||
            'client_id' => $client->id,
 | 
			
		||||
            'company_id' => $company->id,
 | 
			
		||||
        ]);
 | 
			
		||||
 | 
			
		||||
        $invoice = Invoice::factory()->create([
 | 
			
		||||
            'user_id' => $user->id,
 | 
			
		||||
            'client_id' => $client->id,
 | 
			
		||||
            'company_id' => $company->id,
 | 
			
		||||
            'number' => (string)$this->faker->randomNumber(6),
 | 
			
		||||
        ]);     
 | 
			
		||||
 | 
			
		||||
        $invoice = InvoiceFactory::create($company->id,$user->id);
 | 
			
		||||
        $invoice->client_id = $client->id;
 | 
			
		||||
        $invoice->status_id = Invoice::STATUS_DRAFT;
 | 
			
		||||
 | 
			
		||||
        $line_items = [];
 | 
			
		||||
 | 
			
		||||
        $item = InvoiceItemFactory::create();
 | 
			
		||||
        $item->quantity = 1;
 | 
			
		||||
        $item->cost = 325;
 | 
			
		||||
        $item->type_id = 1;
 | 
			
		||||
 | 
			
		||||
        $line_items[] = $item;
 | 
			
		||||
 | 
			
		||||
        $invoice->line_items = $line_items;
 | 
			
		||||
 | 
			
		||||
        $invoice = $invoice->calc()->getInvoice();
 | 
			
		||||
 | 
			
		||||
        $this->assertEquals(0, $client->balance);
 | 
			
		||||
        $this->assertEquals(0, $client->paid_to_date);
 | 
			
		||||
        $this->assertEquals(0, $invoice->balance);
 | 
			
		||||
//mark sent
 | 
			
		||||
 | 
			
		||||
        $invoice = $invoice->service()->markSent()->save();
 | 
			
		||||
 | 
			
		||||
        $invoice->fresh();
 | 
			
		||||
        $invoice->client->fresh();
 | 
			
		||||
 | 
			
		||||
        $this->assertEquals(325, $invoice->balance);
 | 
			
		||||
        $this->assertEquals(0, $invoice->client->fresh()->paid_to_date);
 | 
			
		||||
        $this->assertEquals(325, $invoice->client->balance);
 | 
			
		||||
 | 
			
		||||
//payment 163
 | 
			
		||||
//
 | 
			
		||||
        $data = [
 | 
			
		||||
            'amount' => 163.0,
 | 
			
		||||
            'client_id' => $this->encodePrimaryKey($client->id),
 | 
			
		||||
            'invoices' => [
 | 
			
		||||
                    [
 | 
			
		||||
                        'invoice_id' => $this->encodePrimaryKey($invoice->id),
 | 
			
		||||
                        'amount' => 163,
 | 
			
		||||
                    ],
 | 
			
		||||
                ],
 | 
			
		||||
            'date' => '2019/12/12',
 | 
			
		||||
        ];
 | 
			
		||||
 | 
			
		||||
        $response = $this->withHeaders([
 | 
			
		||||
            'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
            'X-API-TOKEN' => $token->token,
 | 
			
		||||
        ])->post('/api/v1/payments/', $data);
 | 
			
		||||
 | 
			
		||||
        $arr = $response->json();
 | 
			
		||||
        $payment_id = $arr['data']['id'];
 | 
			
		||||
        $payment_1 = Payment::whereId($this->decodePrimaryKey($payment_id))->first();
 | 
			
		||||
 | 
			
		||||
//payment 162
 | 
			
		||||
        $this->assertEquals(162, $invoice->fresh()->balance);
 | 
			
		||||
        $this->assertEquals(162, $invoice->client->fresh()->balance);
 | 
			
		||||
        $this->assertEquals(163, $invoice->client->fresh()->paid_to_date);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        $data = [
 | 
			
		||||
            'amount' => 162.0,
 | 
			
		||||
            'client_id' => $this->encodePrimaryKey($client->id),
 | 
			
		||||
            'invoices' => [
 | 
			
		||||
                    [
 | 
			
		||||
                        'invoice_id' => $this->encodePrimaryKey($invoice->id),
 | 
			
		||||
                        'amount' => 162,
 | 
			
		||||
                    ],
 | 
			
		||||
                ],
 | 
			
		||||
            'date' => '2019/12/12',
 | 
			
		||||
        ];
 | 
			
		||||
 | 
			
		||||
        $response = $this->withHeaders([
 | 
			
		||||
            'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
            'X-API-TOKEN' => $token->token,
 | 
			
		||||
        ])->post('/api/v1/payments/', $data);
 | 
			
		||||
 | 
			
		||||
        $arr = $response->json();
 | 
			
		||||
        $payment_id = $arr['data']['id'];
 | 
			
		||||
        $payment_2 = Payment::whereId($this->decodePrimaryKey($payment_id))->first();
 | 
			
		||||
 | 
			
		||||
        $this->assertEquals(0, $invoice->fresh()->balance);
 | 
			
		||||
        $this->assertEquals(0, $invoice->client->fresh()->balance);
 | 
			
		||||
        $this->assertEquals(325, $invoice->client->fresh()->paid_to_date);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//refund payment 2 by 63 dollars
 | 
			
		||||
 | 
			
		||||
        $data = [
 | 
			
		||||
            'id' => $this->encodePrimaryKey($payment_2->id),
 | 
			
		||||
            'amount' => 63,
 | 
			
		||||
            'date' => '2021/12/12',
 | 
			
		||||
            'invoices' => [
 | 
			
		||||
                [
 | 
			
		||||
                'invoice_id' => $invoice->hashed_id,
 | 
			
		||||
                'amount' => 63,
 | 
			
		||||
                ],
 | 
			
		||||
            ],
 | 
			
		||||
        ];
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        $response = $this->withHeaders([
 | 
			
		||||
            'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
            'X-API-TOKEN' => $token->token,
 | 
			
		||||
        ])->post('/api/v1/payments/refund', $data);
 | 
			
		||||
 | 
			
		||||
        $this->assertEquals(63, $invoice->fresh()->balance);
 | 
			
		||||
        $this->assertEquals(63, $invoice->client->fresh()->balance);               
 | 
			
		||||
        $this->assertEquals(262, $invoice->client->fresh()->paid_to_date);
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
//delete payment 2
 | 
			
		||||
        //
 | 
			
		||||
        $data = [
 | 
			
		||||
            'ids' => [$this->encodePrimaryKey($payment_2->id)],
 | 
			
		||||
        ];
 | 
			
		||||
 | 
			
		||||
        $response = $this->withHeaders([
 | 
			
		||||
            'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
            'X-API-TOKEN' => $token->token,
 | 
			
		||||
        ])->post('/api/v1/payments/bulk?action=delete', $data);
 | 
			
		||||
 | 
			
		||||
        $this->assertEquals(162, $invoice->fresh()->balance);
 | 
			
		||||
        $this->assertEquals(162, $invoice->client->fresh()->balance);   
 | 
			
		||||
        $this->assertEquals(163, $invoice->client->fresh()->paid_to_date);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// Pay 162 again and create payment #3
 | 
			
		||||
 | 
			
		||||
        $data = [
 | 
			
		||||
            'amount' => 162.0,
 | 
			
		||||
            'client_id' => $this->encodePrimaryKey($client->id),
 | 
			
		||||
            'invoices' => [
 | 
			
		||||
                    [
 | 
			
		||||
                        'invoice_id' => $this->encodePrimaryKey($invoice->id),
 | 
			
		||||
                        'amount' => 162,
 | 
			
		||||
                    ],
 | 
			
		||||
                ],
 | 
			
		||||
            'date' => '2019/12/12',
 | 
			
		||||
        ];
 | 
			
		||||
 | 
			
		||||
        $response = $this->withHeaders([
 | 
			
		||||
            'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
            'X-API-TOKEN' => $token->token,
 | 
			
		||||
        ])->post('/api/v1/payments/', $data);         
 | 
			
		||||
 | 
			
		||||
        $arr = $response->json();
 | 
			
		||||
        $payment_id = $arr['data']['id'];
 | 
			
		||||
        $payment_3 = Payment::whereId($this->decodePrimaryKey($payment_id))->first();
 | 
			
		||||
 | 
			
		||||
        $invoice->fresh();
 | 
			
		||||
        $invoice->client->fresh();
 | 
			
		||||
 | 
			
		||||
        $this->assertEquals(0, $invoice->fresh()->balance);
 | 
			
		||||
        $this->assertEquals(0, $invoice->client->fresh()->balance);
 | 
			
		||||
        $this->assertEquals(325, $invoice->client->fresh()->paid_to_date);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//refund payment 3 by 63
 | 
			
		||||
    
 | 
			
		||||
        $data = [
 | 
			
		||||
            'id' => $this->encodePrimaryKey($payment_3->id),
 | 
			
		||||
            'amount' => 63,
 | 
			
		||||
            'date' => '2021/12/12',
 | 
			
		||||
            'invoices' => [
 | 
			
		||||
                [
 | 
			
		||||
                'invoice_id' => $invoice->hashed_id,
 | 
			
		||||
                'amount' => 63,
 | 
			
		||||
                ],
 | 
			
		||||
            ],
 | 
			
		||||
        ];
 | 
			
		||||
 | 
			
		||||
        $response = $this->withHeaders([
 | 
			
		||||
            'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
            'X-API-TOKEN' => $token->token,
 | 
			
		||||
        ])->post('/api/v1/payments/refund', $data);
 | 
			
		||||
 | 
			
		||||
        $this->assertEquals(63, $invoice->fresh()->balance);
 | 
			
		||||
        $this->assertEquals(63, $invoice->client->fresh()->balance);
 | 
			
		||||
        $this->assertEquals(262, $invoice->client->fresh()->paid_to_date);
 | 
			
		||||
 | 
			
		||||
//payment 4 for 63
 | 
			
		||||
        $data = [
 | 
			
		||||
            'amount' => 63.0,
 | 
			
		||||
            'client_id' => $this->encodePrimaryKey($client->id),
 | 
			
		||||
            'invoices' => [
 | 
			
		||||
                    [
 | 
			
		||||
                        'invoice_id' => $this->encodePrimaryKey($invoice->id),
 | 
			
		||||
                        'amount' => 63,
 | 
			
		||||
                    ],
 | 
			
		||||
                ],
 | 
			
		||||
            'date' => '2019/12/12',
 | 
			
		||||
        ];
 | 
			
		||||
 | 
			
		||||
        $response = $this->withHeaders([
 | 
			
		||||
            'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
            'X-API-TOKEN' => $token->token,
 | 
			
		||||
        ])->post('/api/v1/payments/', $data);         
 | 
			
		||||
 | 
			
		||||
        $arr = $response->json();
 | 
			
		||||
        $payment_id = $arr['data']['id'];
 | 
			
		||||
        $payment_4 = Payment::whereId($this->decodePrimaryKey($payment_id))->first();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        $this->assertEquals(0, $invoice->fresh()->balance);
 | 
			
		||||
        $this->assertEquals(0, $invoice->client->fresh()->balance);
 | 
			
		||||
        $this->assertEquals(325, $invoice->client->fresh()->paid_to_date);
 | 
			
		||||
 | 
			
		||||
// delete payment 3
 | 
			
		||||
// 
 | 
			
		||||
 | 
			
		||||
        //
 | 
			
		||||
        $data = [
 | 
			
		||||
            'ids' => [$this->encodePrimaryKey($payment_4->id)],
 | 
			
		||||
        ];
 | 
			
		||||
 | 
			
		||||
        $response = $this->withHeaders([
 | 
			
		||||
            'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
            'X-API-TOKEN' => $token->token,
 | 
			
		||||
        ])->post('/api/v1/payments/bulk?action=delete', $data);
 | 
			
		||||
 | 
			
		||||
        $this->assertEquals(63, $invoice->fresh()->balance);
 | 
			
		||||
        $this->assertEquals(63, $invoice->client->fresh()->balance);   
 | 
			
		||||
        $this->assertEquals(262, $invoice->client->fresh()->paid_to_date);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//set discount of 63 to invoice
 | 
			
		||||
 | 
			
		||||
        $invoice = $invoice->fresh();
 | 
			
		||||
        $invoice->discount = 63;
 | 
			
		||||
        $invoice->is_amount_discount = true;
 | 
			
		||||
        $invoice->save();
 | 
			
		||||
 | 
			
		||||
        $invoice->calc()->getInvoice()->save();
 | 
			
		||||
        $invoice->service()->updateStatus()->save();
 | 
			
		||||
        $invoice->ledger()->updateInvoiceBalance(-63, "Update adjustment for invoice {$invoice->number}");
 | 
			
		||||
        $invoice->client->service()->updateBalance(-63)->save();
 | 
			
		||||
 | 
			
		||||
        $this->assertEquals(0, $invoice->fresh()->balance);
 | 
			
		||||
        $this->assertEquals(0, $invoice->client->fresh()->balance);  
 | 
			
		||||
        $this->assertEquals(262, $invoice->client->fresh()->paid_to_date);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//now delete the invoice
 | 
			
		||||
 | 
			
		||||
        $data = [
 | 
			
		||||
            'ids' => [$invoice->hashed_id],
 | 
			
		||||
        ];
 | 
			
		||||
 | 
			
		||||
        $response = $this->withHeaders([
 | 
			
		||||
                'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
                'X-API-TOKEN' => $token->token,
 | 
			
		||||
            ])->post('/api/v1/invoices/bulk?action=delete', $data);
 | 
			
		||||
 | 
			
		||||
        $this->assertEquals(0, $invoice->fresh()->balance);
 | 
			
		||||
        $this->assertEquals(0, $invoice->client->fresh()->balance);  
 | 
			
		||||
        $this->assertEquals(0, $invoice->client->fresh()->paid_to_date);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//Delete payment 4 which is for $162
 | 
			
		||||
        $data = [
 | 
			
		||||
            'ids' => [$this->encodePrimaryKey($payment_1->id)],
 | 
			
		||||
        ];
 | 
			
		||||
 | 
			
		||||
        $response = $this->withHeaders([
 | 
			
		||||
            'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
            'X-API-TOKEN' => $token->token,
 | 
			
		||||
        ])->post('/api/v1/payments/bulk?action=delete', $data);
 | 
			
		||||
 | 
			
		||||
        $this->assertEquals(0, $invoice->fresh()->balance);
 | 
			
		||||
        $this->assertEquals(0, $invoice->client->fresh()->balance);  
 | 
			
		||||
        $this->assertEquals(0, $invoice->client->fresh()->paid_to_date);
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user