mirror of
				https://github.com/invoiceninja/invoiceninja.git
				synced 2025-10-31 16:17:32 -04:00 
			
		
		
		
	Merge pull request #3871 from turbo124/v2
Allow NPM/NODE paths to be configurable
This commit is contained in:
		
						commit
						0d92d1675a
					
				| @ -30,7 +30,7 @@ Please Note: Your APP_KEY in the .env file is used to encrypt data, if you lose | ||||
| 
 | ||||
| Run if you want to load sample data, remember to configure .env | ||||
| ``` | ||||
| php artisan migrate:fresh --seed && php artisan db:seed --class=RandomDataSeeder | ||||
| php artisan migrate:fresh --seed && php artisan db:seed && php artisan ninja:create-test-data | ||||
| ``` | ||||
| 
 | ||||
| To Run the web server | ||||
| @ -42,6 +42,10 @@ Navigate to (replace ninja.test as required) | ||||
| ``` | ||||
| http://ninja.test:8000/setup - To setup your configuration if you didn't load sample data. | ||||
| http://ninja.test:8000/ - For Administrator Logon | ||||
| 
 | ||||
| user: small@example.com | ||||
| pass: password | ||||
| 
 | ||||
| http://ninja.test:8000/client/login - For Client Portal | ||||
| 
 | ||||
| user: user@example.com | ||||
|  | ||||
| @ -304,7 +304,7 @@ class CheckData extends Command | ||||
|             if($ledger && number_format($invoice_balance, 4) != number_format($client->balance, 4)) | ||||
|             { | ||||
|                 $wrong_balances++; | ||||
|                 $this->logMessage($client->present()->name . " - " . $client->id . " - balances do not match {$invoice_balance} - {$client->balance} - {$ledger->balance}"); | ||||
|                 $this->logMessage($client->present()->name . " - " . $client->id . " - balances do not match Invoice Balance = {$invoice_balance} Client Balance = {$client->balance} Ledger Balance = {$ledger->balance}"); | ||||
| 
 | ||||
|                 $this->isValid = false; | ||||
| 
 | ||||
|  | ||||
| @ -11,7 +11,9 @@ | ||||
| 
 | ||||
| namespace App\Repositories; | ||||
| 
 | ||||
| use App\Events\Credit\CreditWasUpdated; | ||||
| use App\Events\Invoice\InvoiceWasUpdated; | ||||
| use App\Events\Quote\QuoteWasUpdated; | ||||
| use App\Factory\InvoiceInvitationFactory; | ||||
| use App\Factory\QuoteInvitationFactory; | ||||
| use App\Jobs\Product\UpdateOrCreateProduct; | ||||
| @ -72,9 +74,7 @@ class BaseRepository | ||||
|         } | ||||
|          | ||||
|         $entity->delete(); | ||||
|          | ||||
|         info("archived"); | ||||
|          | ||||
|                  | ||||
|         $className = $this->getEventClass($entity, 'Archived'); | ||||
| 
 | ||||
|         if (class_exists($className)) { | ||||
| @ -192,10 +192,6 @@ class BaseRepository | ||||
|      */ | ||||
|     protected function alternativeSave($data, $model) | ||||
|     { | ||||
|         $new_entity = false; | ||||
| 
 | ||||
|         if(!$model->id) | ||||
|             $new_entity = true; | ||||
| 
 | ||||
|         $class = new ReflectionClass($model); | ||||
| 
 | ||||
| @ -234,9 +230,6 @@ class BaseRepository | ||||
|         $model->fill($tmp_data); | ||||
|         $model->save(); | ||||
| 
 | ||||
|         if($new_entity) | ||||
|             $this->newEntityEvent($model); | ||||
| 
 | ||||
|         if (array_key_exists('documents', $data)) { | ||||
|             $this->saveDocuments($data['documents'], $model); | ||||
|         } | ||||
| @ -291,10 +284,9 @@ class BaseRepository | ||||
|         } | ||||
| 
 | ||||
|         $model = $model->calc()->getInvoice(); | ||||
|          | ||||
|         $state['finished_amount'] = $model->amount; | ||||
|          | ||||
|         info("finished amount = {$model->amount}"); | ||||
| 
 | ||||
|         $model = $model->service()->applyNumber()->save(); | ||||
|          | ||||
|         if ($model->company->update_products !== false) { | ||||
| @ -302,8 +294,9 @@ class BaseRepository | ||||
|         } | ||||
| 
 | ||||
|         if ($class->name == Invoice::class) { | ||||
| 
 | ||||
|             if (($state['finished_amount'] != $state['starting_amount']) && ($model->status_id != Invoice::STATUS_DRAFT)) { | ||||
|                 info("inside ledger updating"); | ||||
| 
 | ||||
|                 $model->ledger()->updateInvoiceBalance(($state['finished_amount'] - $state['starting_amount'])); | ||||
|                 $model->client->service()->updateBalance(($state['finished_amount'] - $state['starting_amount']))->save(); | ||||
|             } | ||||
| @ -311,8 +304,6 @@ class BaseRepository | ||||
|             if(!$model->design_id) | ||||
|                 $model->design_id = $this->decodePrimaryKey($client->getSetting('invoice_design_id')); | ||||
| 
 | ||||
|             event(new InvoiceWasUpdated($model, $model->company)); | ||||
| 
 | ||||
|         } | ||||
| 
 | ||||
|         if ($class->name == Credit::class) { | ||||
| @ -320,6 +311,8 @@ class BaseRepository | ||||
| 
 | ||||
|             if(!$model->design_id) | ||||
|                 $model->design_id = $this->decodePrimaryKey($client->getSetting('credit_design_id')); | ||||
| 
 | ||||
| 
 | ||||
|         } | ||||
|          | ||||
|         if ($class->name == Quote::class) { | ||||
| @ -327,22 +320,14 @@ class BaseRepository | ||||
| 
 | ||||
|             if(!$model->design_id) | ||||
|                 $model->design_id = $this->decodePrimaryKey($client->getSetting('quote_design_id')); | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|         } | ||||
| 
 | ||||
|         $model->save(); | ||||
| 
 | ||||
|         return $model->fresh(); | ||||
|     } | ||||
| 
 | ||||
|     public function newEntityEvent($model) | ||||
|     { | ||||
| 
 | ||||
|         $className = $this->getEventClass($model, 'Created'); | ||||
| 
 | ||||
|         if (class_exists($className)) { | ||||
|             event(new $className($model, $model->company)); | ||||
|         } | ||||
| 
 | ||||
|     } | ||||
|      | ||||
| } | ||||
|  | ||||
| @ -1,302 +0,0 @@ | ||||
| <?php | ||||
| 
 | ||||
| namespace App\Services\Payment; | ||||
| 
 | ||||
| use App\Exceptions\PaymentRefundFailed; | ||||
| use App\Factory\CreditFactory; | ||||
| use App\Factory\InvoiceItemFactory; | ||||
| use App\Models\Activity; | ||||
| use App\Models\CompanyGateway; | ||||
| use App\Models\Credit; | ||||
| use App\Models\Invoice; | ||||
| use App\Models\Payment; | ||||
| use App\Repositories\ActivityRepository; | ||||
| 
 | ||||
| class RefundPayment | ||||
| { | ||||
|     public $payment; | ||||
| 
 | ||||
|     public $refund_data; | ||||
| 
 | ||||
|     private $credit_note; | ||||
| 
 | ||||
|     private $total_refund; | ||||
| 
 | ||||
|     private $gateway_refund_status; | ||||
| 
 | ||||
|     private $activity_repository; | ||||
| 
 | ||||
|     public function __construct($payment, $refund_data) | ||||
|     { | ||||
|         $this->payment = $payment; | ||||
| 
 | ||||
|         $this->refund_data = $refund_data; | ||||
| 
 | ||||
|         $this->total_refund = 0; | ||||
| 
 | ||||
|         $this->gateway_refund_status = false; | ||||
| 
 | ||||
|         $this->activity_repository = new ActivityRepository(); | ||||
|     } | ||||
| 
 | ||||
|     public function run() | ||||
|     { | ||||
| 
 | ||||
|         return $this->calculateTotalRefund() //sets amount for the refund (needed if we are refunding multiple invoices in one payment)
 | ||||
|             ->setStatus() //sets status of payment
 | ||||
|             ->buildCreditNote() //generate the credit note
 | ||||
|             ->buildCreditLineItems() //generate the credit note items
 | ||||
|             ->updateCreditables() //return the credits first
 | ||||
|             ->updatePaymentables() //update the paymentable items
 | ||||
|             ->adjustInvoices() | ||||
|             ->processGatewayRefund() //process the gateway refund if needed
 | ||||
|             ->save(); | ||||
|     } | ||||
| 
 | ||||
|     private function processGatewayRefund() | ||||
|     { | ||||
|         if ($this->refund_data['gateway_refund'] !== false && $this->total_refund > 0) { | ||||
|             $gateway = CompanyGateway::first(); | ||||
| 
 | ||||
|             if ($gateway) { | ||||
|                 $response = $gateway->driver($this->payment->client)->refund($this->payment, $this->total_refund); | ||||
| 
 | ||||
|                 if ($response['success']) { | ||||
|                     throw new PaymentRefundFailed(); | ||||
|                 } | ||||
| 
 | ||||
|                 $this->payment->refunded = $this->total_refund; | ||||
| 
 | ||||
|                 $this | ||||
|                     ->createActivity($gateway) | ||||
|                     ->updateCreditNoteBalance(); | ||||
|             } | ||||
|         } else { | ||||
|             $this->payment->refunded += $this->total_refund; | ||||
|         } | ||||
| 
 | ||||
|         return $this; | ||||
|     } | ||||
| 
 | ||||
|     public function updateCreditNoteBalance() | ||||
|     { | ||||
|         $this->credit_note->balance -= $this->total_refund; | ||||
|         $this->credit_note->status_id = Credit::STATUS_APPLIED; | ||||
| 
 | ||||
|         $this->credit_note->balance === 0 | ||||
|             ? $this->credit_note->status_id = Credit::STATUS_APPLIED | ||||
|             : $this->credit_note->status_id = Credit::STATUS_PARTIAL; | ||||
| 
 | ||||
|         $this->credit_note->save(); | ||||
| 
 | ||||
|         return $this; | ||||
|     } | ||||
| 
 | ||||
|     private function createActivity($notes) | ||||
|     { | ||||
|         $fields = new \stdClass; | ||||
|         $activity_repo = new ActivityRepository(); | ||||
| 
 | ||||
|         $fields->payment_id = $this->payment->id; | ||||
|         $fields->user_id = $this->payment->user_id; | ||||
|         $fields->company_id = $this->payment->company_id; | ||||
|         $fields->activity_type_id = Activity::REFUNDED_PAYMENT; | ||||
|         $fields->credit_id = $this->credit_note->id; | ||||
|         $fields->notes = json_encode($notes); | ||||
| 
 | ||||
|         if (isset($this->refund_data['invoices'])) { | ||||
|             foreach ($this->refund_data['invoices'] as $invoice) { | ||||
|                 $fields->invoice_id = $invoice['invoice_id']; | ||||
|                 $activity_repo->save($fields, $this->payment); | ||||
|             } | ||||
|         } else { | ||||
|             $activity_repo->save($fields, $this->payment); | ||||
|         } | ||||
| 
 | ||||
|         return $this; | ||||
|     } | ||||
| 
 | ||||
|     private function calculateTotalRefund() | ||||
|     { | ||||
| 
 | ||||
|         if (array_key_exists('invoices', $this->refund_data) && count($this->refund_data['invoices']) > 0){ | ||||
|             info("array of invoice to refund"); | ||||
|             $this->total_refund = collect($this->refund_data['invoices'])->sum('amount'); | ||||
|         } | ||||
|         else{ | ||||
|             info("no invoices found - refunding total."); | ||||
|             $this->total_refund = $this->refund_data['amount']; | ||||
|         } | ||||
| 
 | ||||
|         return $this; | ||||
|     } | ||||
| 
 | ||||
|     private function setStatus() | ||||
|     { | ||||
|         if ($this->refund_data['amount'] == $this->payment->amount) { | ||||
|             $this->payment->status_id = Payment::STATUS_REFUNDED; | ||||
|         } else { | ||||
|             $this->payment->status_id = Payment::STATUS_PARTIALLY_REFUNDED; | ||||
|         } | ||||
| 
 | ||||
|         return $this; | ||||
|     } | ||||
| 
 | ||||
|     private function buildCreditNote() | ||||
|     { | ||||
|         $this->credit_note = CreditFactory::create($this->payment->company_id, $this->payment->user_id); | ||||
|         $this->credit_note->assigned_user_id = isset($this->payment->assigned_user_id) ?: null; | ||||
|         $this->credit_note->date = $this->refund_data['date']; | ||||
|         $this->credit_note->status_id = Credit::STATUS_SENT; | ||||
|         $this->credit_note->client_id = $this->payment->client->id; | ||||
|         $this->credit_note->amount = $this->total_refund; | ||||
|         $this->credit_note->balance = $this->total_refund; | ||||
| 
 | ||||
|         $this->credit_note->save(); | ||||
|         $this->credit_note->number = $this->payment->client->getNextCreditNumber($this->payment->client); | ||||
|         $this->credit_note->save(); | ||||
| 
 | ||||
|         return $this; | ||||
|     } | ||||
| 
 | ||||
|     private function buildCreditLineItems() | ||||
|     { | ||||
|         $ledger_string = ''; | ||||
| 
 | ||||
|         if (isset($this->refund_data['invoices']) && count($this->refund_data['invoices']) > 0) { | ||||
|             foreach ($this->refund_data['invoices'] as $invoice) { | ||||
| 
 | ||||
|                 $inv = Invoice::find($invoice['invoice_id']); | ||||
| 
 | ||||
|                 $credit_line_item = InvoiceItemFactory::create(); | ||||
|                 $credit_line_item->quantity = 1; | ||||
|                 $credit_line_item->cost = $invoice['amount']; | ||||
|                 $credit_line_item->product_key = ctrans('texts.invoice'); | ||||
|                 $credit_line_item->notes = ctrans('texts.refund_body', ['amount' => $invoice['amount'], 'invoice_number' => $inv->number]); | ||||
|                 $credit_line_item->line_total = $invoice['amount']; | ||||
|                 $credit_line_item->date = $this->refund_data['date']; | ||||
| 
 | ||||
|                 $ledger_string .= $credit_line_item->notes . ' '; | ||||
| 
 | ||||
|                 $line_items[] = $credit_line_item; | ||||
|             } | ||||
|         } else { | ||||
| 
 | ||||
|             $credit_line_item = InvoiceItemFactory::create(); | ||||
|             $credit_line_item->quantity = 1; | ||||
|             $credit_line_item->cost = $this->refund_data['amount']; | ||||
|             $credit_line_item->product_key = ctrans('texts.credit'); | ||||
|             $credit_line_item->notes = ctrans('texts.credit_created_by', ['transaction_reference' => $this->payment->number]); | ||||
|             $credit_line_item->line_total = $this->refund_data['amount']; | ||||
|             $credit_line_item->date = $this->refund_data['date']; | ||||
| 
 | ||||
|             $line_items = []; | ||||
|             $line_items[] = $credit_line_item; | ||||
|         } | ||||
| 
 | ||||
|         $this->credit_note->line_items = $line_items; | ||||
|         $this->credit_note->save(); | ||||
| 
 | ||||
|         return $this; | ||||
|     } | ||||
| 
 | ||||
|     private function updatePaymentables() | ||||
|     { | ||||
|         if (isset($this->refund_data['invoices']) && count($this->refund_data['invoices']) > 0) { | ||||
|             $this->payment->invoices->each(function ($paymentable_invoice) { | ||||
| 
 | ||||
|                 collect($this->refund_data['invoices'])->each(function ($refunded_invoice) use ($paymentable_invoice) { | ||||
| 
 | ||||
|                     if ($refunded_invoice['invoice_id'] == $paymentable_invoice->id) { | ||||
|                         $paymentable_invoice->pivot->refunded += $refunded_invoice['amount']; | ||||
|                         $paymentable_invoice->pivot->save(); | ||||
|                     } | ||||
|                 }); | ||||
|             }); | ||||
|         } | ||||
| 
 | ||||
|         return $this; | ||||
|     } | ||||
| 
 | ||||
|     private function updateCreditables() | ||||
|     { | ||||
| 
 | ||||
|         if ($this->payment->credits()->exists()) { | ||||
|             //Adjust credits first!!!
 | ||||
|             foreach ($this->payment->credits as $paymentable_credit) { | ||||
|                 $available_credit = $paymentable_credit->pivot->amount - $paymentable_credit->pivot->refunded; | ||||
| 
 | ||||
|                 if ($available_credit > $this->total_refund) { | ||||
|                     $paymentable_credit->pivot->refunded += $this->total_refund; | ||||
|                     $paymentable_credit->pivot->save(); | ||||
| 
 | ||||
|                     $paymentable_credit->balance += $this->total_refund; | ||||
|                     $paymentable_credit->save(); | ||||
| 
 | ||||
|                     $this->total_refund = 0; | ||||
|                 } else { | ||||
|                     $paymentable_credit->pivot->refunded += $available_credit; | ||||
|                     $paymentable_credit->pivot->save(); | ||||
| 
 | ||||
|                     $paymentable_credit->balance += $available_credit; | ||||
|                     $paymentable_credit->save(); | ||||
| 
 | ||||
|                     $this->total_refund -= $available_credit; | ||||
|                 } | ||||
| 
 | ||||
|                 if ($this->total_refund == 0) { | ||||
|                     break; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         return $this; | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     private function adjustInvoices() | ||||
|     { | ||||
|         $adjustment_amount = 0; | ||||
| 
 | ||||
|         if (isset($this->refund_data['invoices']) && count($this->refund_data['invoices']) > 0) { | ||||
|             foreach ($this->refund_data['invoices'] as $refunded_invoice) { | ||||
|                 $invoice = Invoice::find($refunded_invoice['invoice_id']); | ||||
| 
 | ||||
|                 $invoice->service()->updateBalance($refunded_invoice['amount'])->save(); | ||||
| 
 | ||||
|                 if ($invoice->amount == $invoice->balance) { | ||||
|                     $invoice->service()->setStatus(Invoice::STATUS_SENT); | ||||
|                 } else { | ||||
|                     $invoice->service()->setStatus(Invoice::STATUS_PARTIAL); | ||||
|                 } | ||||
| 
 | ||||
|                 $invoice->save(); | ||||
| 
 | ||||
|                 $client = $invoice->client; | ||||
| 
 | ||||
|                 $adjustment_amount += $refunded_invoice['amount']; | ||||
|                 $client->balance += $refunded_invoice['amount']; | ||||
| 
 | ||||
|                 $client->save(); | ||||
| 
 | ||||
|                 //todo adjust ledger balance here? or after and reference the credit and its total
 | ||||
|             } | ||||
| 
 | ||||
|             $ledger_string = ''; //todo
 | ||||
| 
 | ||||
|             $this->credit_note->ledger()->updateCreditBalance($adjustment_amount, $ledger_string); | ||||
| 
 | ||||
|             $this->payment->client->paid_to_date -= $this->refund_data['amount']; | ||||
|             $this->payment->client->save(); | ||||
|         } | ||||
| 
 | ||||
|         return $this; | ||||
|     } | ||||
| 
 | ||||
|     private function save() | ||||
|     { | ||||
|         $this->payment->save(); | ||||
| 
 | ||||
|         return $this->payment; | ||||
|     } | ||||
| } | ||||
| @ -27,7 +27,23 @@ trait PdfMaker | ||||
|      */ | ||||
|     public function makePdf($header, $footer, $html) | ||||
|     { | ||||
|          | ||||
| 
 | ||||
|         $browser = Browsershot::html($html); | ||||
| 
 | ||||
|         if(config('ninja.system.node_path')) | ||||
|             $browser->setNodeBinary(config('ninja.system.node_path')); | ||||
| 
 | ||||
|         if(config('ninja.system.npm_path')) | ||||
|             $browser->setNpmBinary(config('ninja.system.npm_path')); | ||||
| 
 | ||||
|         return $browser->deviceScaleFactor(1) | ||||
|                 ->showBackground() | ||||
|                 ->deviceScaleFactor(1) | ||||
|                 ->waitUntilNetworkIdle(true) | ||||
|                 ->pdf(); | ||||
| 
 | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|         // if($header && $footer){
 | ||||
| @ -46,19 +62,9 @@ trait PdfMaker | ||||
|         // else {
 | ||||
|         //     $browser = Browsershot::html($html);
 | ||||
|         // }
 | ||||
| 
 | ||||
|         $browser = Browsershot::html($html); | ||||
| 
 | ||||
|         // $browser->format('A4');
 | ||||
|         // $browser->landscape();
 | ||||
| 
 | ||||
|         return $browser->deviceScaleFactor(1) | ||||
|                 ->showBackground() | ||||
|                 ->deviceScaleFactor(1) | ||||
|                 ->waitUntilNetworkIdle(true) | ||||
|                 ->pdf(); | ||||
| 
 | ||||
|         // return Browsershot::html($html)
 | ||||
|         // 
 | ||||
|         // 
 | ||||
|         //         // return Browsershot::html($html)
 | ||||
|         // //->showBrowserHeaderAndFooter()
 | ||||
|         // //->headerHtml($header)
 | ||||
|         // //->footerHtml($footer)
 | ||||
| @ -67,5 +73,6 @@ trait PdfMaker | ||||
|         //     ->waitUntilNetworkIdle(true)    ->pdf();
 | ||||
|         // //->margins(10,10,10,10)
 | ||||
|         // //->savePdf('test.pdf');
 | ||||
|     } | ||||
| } | ||||
|         // 
 | ||||
|         // $browser->format('A4');
 | ||||
|         // $browser->landscape();
 | ||||
| @ -121,5 +121,9 @@ return [ | ||||
|             'client_id' => env('GOOGLE_CLIENT_ID', ''), | ||||
|             'client_secret' => env('GOOGLE_CLIENT_SECRET','') | ||||
|         ] | ||||
|     ], | ||||
|     'system' => [ | ||||
|         'node_path' => env('NODE_PATH', false), | ||||
|         'npm_path' => env('NPM_PATH', false) | ||||
|     ] | ||||
| ]; | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user