diff --git a/.env.example b/.env.example index 7cfcb0b572ee..6411259c0ef4 100644 --- a/.env.example +++ b/.env.example @@ -5,9 +5,6 @@ APP_DEBUG=true APP_URL=http://localhost -USER_AUTH_PROVIDER=users -CONTACT_AUTH_PROVIDER=contacts - DB_CONNECTION=db-ninja-01 MULTI_DB_ENABLED=true diff --git a/.env.travis b/.env.travis index 4daab15e9ac3..2ad583a420ab 100644 --- a/.env.travis +++ b/.env.travis @@ -19,6 +19,5 @@ TRAVIS=true API_SECRET=password TEST_USERNAME=user@example.com TEST_PERMISSIONS_USERNAME=permissions@example.com -USER_AUTH_PROVIDER=users -CONTACT_AUTH_PROVIDER=contacts + MULTI_DB_ENABLED=true diff --git a/app/Console/Commands/CreateTestData.php b/app/Console/Commands/CreateTestData.php index 11e450de2291..7ee74296c3f3 100644 --- a/app/Console/Commands/CreateTestData.php +++ b/app/Console/Commands/CreateTestData.php @@ -2,6 +2,9 @@ namespace App\Console\Commands; +use App\Console\Commands\TestData\CreateTestCreditJob; +use App\Console\Commands\TestData\CreateTestInvoiceJob; +use App\Console\Commands\TestData\CreateTestQuoteJob; use App\DataMapper\DefaultSettings; use App\Events\Invoice\InvoiceWasCreated; use App\Events\Invoice\InvoiceWasMarkedSent; @@ -81,15 +84,9 @@ class CreateTestData extends Command $account = factory(\App\Models\Account::class)->create(); $company = factory(\App\Models\Company::class)->create([ 'account_id' => $account->id, + 'slack_webhook_url' => config('ninja.notification.slack'), ]); - $settings = $company->settings; - - $settings->system_notifications_slack = config('ninja.notification.slack'); - $settings->system_notifications_email = config('ninja.contact.email'); - - $company->settings = $settings; - $company->save(); $account->default_company_id = $company->id; $account->save(); @@ -172,17 +169,9 @@ class CreateTestData extends Command $account = factory(\App\Models\Account::class)->create(); $company = factory(\App\Models\Company::class)->create([ 'account_id' => $account->id, + 'slack_webhook_url' => config('ninja.notification.slack'), ]); - - $settings = $company->settings; - - $settings->system_notifications_slack = config('ninja.notification.slack'); - $settings->system_notifications_email = config('ninja.contact.email'); - - $company->settings = $settings; - $company->save(); - $account->default_company_id = $company->id; $account->save(); @@ -279,16 +268,9 @@ class CreateTestData extends Command $account = factory(\App\Models\Account::class)->create(); $company = factory(\App\Models\Company::class)->create([ 'account_id' => $account->id, + 'slack_webhook_url' => config('ninja.notification.slack'), ]); - $settings = $company->settings; - - $settings->system_notifications_slack = config('ninja.notification.slack'); - $settings->system_notifications_email = config('ninja.contact.email'); - - $company->settings = $settings; - $company->save(); - $account->default_company_id = $company->id; $account->save(); @@ -367,24 +349,28 @@ class CreateTestData extends Command private function createClient($company, $user) { - $client = factory(\App\Models\Client::class)->create([ - 'user_id' => $user->id, - 'company_id' => $company->id - ]); - factory(\App\Models\ClientContact::class, 1)->create([ + // dispatch(function () use ($company, $user) { + + // }); + $client = factory(\App\Models\Client::class)->create([ 'user_id' => $user->id, - 'client_id' => $client->id, - 'company_id' => $company->id, - 'is_primary' => 1 - ]); - - factory(\App\Models\ClientContact::class, rand(1, 5))->create([ - 'user_id' => $user->id, - 'client_id' => $client->id, 'company_id' => $company->id ]); + factory(\App\Models\ClientContact::class, 1)->create([ + 'user_id' => $user->id, + 'client_id' => $client->id, + 'company_id' => $company->id, + 'is_primary' => 1 + ]); + + factory(\App\Models\ClientContact::class, rand(1, 5))->create([ + 'user_id' => $user->id, + 'client_id' => $client->id, + 'company_id' => $company->id + ]); + } @@ -445,149 +431,162 @@ class CreateTestData extends Command private function createInvoice($client) { - $faker = \Faker\Factory::create(); - - $invoice = InvoiceFactory::create($client->company->id, $client->user->id, $client->getMergedSettings(), $client);//stub the company and user_id - $invoice->client_id = $client->id; -// $invoice->date = $faker->date(); - $dateable = Carbon::now()->subDays(rand(0,90)); - $invoice->date = $dateable; - - $invoice->line_items = $this->buildLineItems(rand(1,10)); - $invoice->uses_inclusive_taxes = false; - - if (rand(0, 1)) { - $invoice->tax_name1 = 'GST'; - $invoice->tax_rate1 = 10.00; + for($x=0; $x<$this->count; $x++){ + dispatch(new CreateTestInvoiceJob($client)); } - if (rand(0, 1)) { - $invoice->tax_name2 = 'VAT'; - $invoice->tax_rate2 = 17.50; - } +// $faker = \Faker\Factory::create(); - if (rand(0, 1)) { - $invoice->tax_name3 = 'CA Sales Tax'; - $invoice->tax_rate3 = 5; - } +// $invoice = InvoiceFactory::create($client->company->id, $client->user->id);//stub the company and user_id +// $invoice->client_id = $client->id; +// // $invoice->date = $faker->date(); +// $dateable = Carbon::now()->subDays(rand(0,90)); +// $invoice->date = $dateable; - $invoice->save(); +// $invoice->line_items = $this->buildLineItems(rand(1,10)); +// $invoice->uses_inclusive_taxes = false; - $invoice_calc = new InvoiceSum($invoice); - $invoice_calc->build(); +// if (rand(0, 1)) { +// $invoice->tax_name1 = 'GST'; +// $invoice->tax_rate1 = 10.00; +// } - $invoice = $invoice_calc->getInvoice(); +// if (rand(0, 1)) { +// $invoice->tax_name2 = 'VAT'; +// $invoice->tax_rate2 = 17.50; +// } - $invoice->save(); - $invoice->service()->createInvitations(); +// if (rand(0, 1)) { +// $invoice->tax_name3 = 'CA Sales Tax'; +// $invoice->tax_rate3 = 5; +// } - $invoice->ledger()->updateInvoiceBalance($invoice->balance); +// $invoice->save(); - //UpdateCompanyLedgerWithInvoice::dispatchNow($invoice, $invoice->balance, $invoice->company); +// $invoice_calc = new InvoiceSum($invoice); +// $invoice_calc->build(); - $this->invoice_repo->markSent($invoice); +// $invoice = $invoice_calc->getInvoice(); - $invoice->service()->createInvitations(); +// $invoice->save(); +// $invoice->service()->createInvitations(); - if (rand(0, 1)) { - $payment = PaymentFactory::create($client->company->id, $client->user->id); - $payment->date = $dateable; - $payment->client_id = $client->id; - $payment->amount = $invoice->balance; - $payment->transaction_reference = rand(0, 500); - $payment->type_id = PaymentType::CREDIT_CARD_OTHER; - $payment->status_id = Payment::STATUS_COMPLETED; - $payment->number = $client->getNextPaymentNumber($client); - $payment->save(); +// $invoice->ledger()->updateInvoiceBalance($invoice->balance); - $payment->invoices()->save($invoice); +// //UpdateCompanyLedgerWithInvoice::dispatchNow($invoice, $invoice->balance, $invoice->company); - event(new PaymentWasCreated($payment, $payment->company)); +// $this->invoice_repo->markSent($invoice); - $payment->service()->updateInvoicePayment(); - //UpdateInvoicePayment::dispatchNow($payment, $payment->company); - } - //@todo this slow things down, but gives us PDFs of the invoices for inspection whilst debugging. - event(new InvoiceWasCreated($invoice, $invoice->company)); +// $invoice->service()->createInvitations(); + +// if (rand(0, 1)) { +// $payment = PaymentFactory::create($client->company->id, $client->user->id); +// $payment->date = $dateable; +// $payment->client_id = $client->id; +// $payment->amount = $invoice->balance; +// $payment->transaction_reference = rand(0, 500); +// $payment->type_id = PaymentType::CREDIT_CARD_OTHER; +// $payment->status_id = Payment::STATUS_COMPLETED; +// $payment->number = $client->getNextPaymentNumber($client); +// $payment->save(); + +// $payment->invoices()->save($invoice); + +// event(new PaymentWasCreated($payment, $payment->company)); + +// $payment->service()->updateInvoicePayment(); +// //UpdateInvoicePayment::dispatchNow($payment, $payment->company); +// } +// //@todo this slow things down, but gives us PDFs of the invoices for inspection whilst debugging. +// event(new InvoiceWasCreated($invoice, $invoice->company)); } private function createCredit($client) { - $faker = \Faker\Factory::create(); + for($x=0; $x<$this->count; $x++){ - $credit = factory(\App\Models\Credit::class)->create(['user_id' => $client->user->id, 'company_id' => $client->company->id, 'client_id' => $client->id]); + dispatch(new CreateTestCreditJob($client)); - //$invoice = InvoiceFactory::create($client->company->id, $client->user->id);//stub the company and user_id - //$invoice->client_id = $client->id; -// $invoice->date = $faker->date(); - $dateable = Carbon::now()->subDays(rand(0,90)); - $credit->date = $dateable; - - $credit->line_items = $this->buildLineItems(rand(1,10)); - $credit->uses_inclusive_taxes = false; - - if (rand(0, 1)) { - $credit->tax_name1 = 'GST'; - $credit->tax_rate1 = 10.00; } +// $faker = \Faker\Factory::create(); - if (rand(0, 1)) { - $credit->tax_name2 = 'VAT'; - $credit->tax_rate2 = 17.50; - } +// $credit = factory(\App\Models\Credit::class)->create(['user_id' => $client->user->id, 'company_id' => $client->company->id, 'client_id' => $client->id]); - if (rand(0, 1)) { - $credit->tax_name3 = 'CA Sales Tax'; - $credit->tax_rate3 = 5; - } +// //$invoice = InvoiceFactory::create($client->company->id, $client->user->id);//stub the company and user_id +// //$invoice->client_id = $client->id; +// // $invoice->date = $faker->date(); +// $dateable = Carbon::now()->subDays(rand(0,90)); +// $credit->date = $dateable; - $credit->save(); +// $credit->line_items = $this->buildLineItems(rand(1,10)); +// $credit->uses_inclusive_taxes = false; - $invoice_calc = new InvoiceSum($credit); - $invoice_calc->build(); +// if (rand(0, 1)) { +// $credit->tax_name1 = 'GST'; +// $credit->tax_rate1 = 10.00; +// } - $credit = $invoice_calc->getCredit(); +// if (rand(0, 1)) { +// $credit->tax_name2 = 'VAT'; +// $credit->tax_rate2 = 17.50; +// } - $credit->save(); +// if (rand(0, 1)) { +// $credit->tax_name3 = 'CA Sales Tax'; +// $credit->tax_rate3 = 5; +// } - event(new CreateCreditInvitation($credit)); +// $credit->save(); + +// $invoice_calc = new InvoiceSum($credit); +// $invoice_calc->build(); + +// $credit = $invoice_calc->getCredit(); + +// $credit->save(); + +// event(new CreateCreditInvitation($credit)); } private function createQuote($client) { - $faker = \Faker\Factory::create(); + for($x=0; $x<$this->count; $x++){ - $quote =factory(\App\Models\Quote::class)->create(['user_id' => $client->user->id, 'company_id' => $client->company->id, 'client_id' => $client->id]); - $quote->date = $faker->date(); - - $quote->line_items = $this->buildLineItems(rand(1,10)); - $quote->uses_inclusive_taxes = false; - - if (rand(0, 1)) { - $quote->tax_name1 = 'GST'; - $quote->tax_rate1 = 10.00; + dispatch(new CreateTestQuoteJob($client)); } + // $faker = \Faker\Factory::create(); - if (rand(0, 1)) { - $quote->tax_name2 = 'VAT'; - $quote->tax_rate2 = 17.50; - } + // $quote =factory(\App\Models\Quote::class)->create(['user_id' => $client->user->id, 'company_id' => $client->company->id, 'client_id' => $client->id]); + // $quote->date = $faker->date(); - if (rand(0, 1)) { - $quote->tax_name3 = 'CA Sales Tax'; - $quote->tax_rate3 = 5; - } + // $quote->line_items = $this->buildLineItems(rand(1,10)); + // $quote->uses_inclusive_taxes = false; - $quote->save(); + // if (rand(0, 1)) { + // $quote->tax_name1 = 'GST'; + // $quote->tax_rate1 = 10.00; + // } - $quote_calc = new InvoiceSum($quote); - $quote_calc->build(); + // if (rand(0, 1)) { + // $quote->tax_name2 = 'VAT'; + // $quote->tax_rate2 = 17.50; + // } - $quote = $quote_calc->getQuote(); - $quote->service()->markSent()->save(); + // if (rand(0, 1)) { + // $quote->tax_name3 = 'CA Sales Tax'; + // $quote->tax_rate3 = 5; + // } - CreateQuoteInvitations::dispatch($quote, $quote->company); + // $quote->save(); + + // $quote_calc = new InvoiceSum($quote); + // $quote_calc->build(); + + // $quote = $quote_calc->getQuote(); + // $quote->service()->markSent()->save(); + + // CreateQuoteInvitations::dispatch($quote, $quote->company); } private function buildLineItems($count = 1) diff --git a/app/Console/Commands/SendTestEmails.php b/app/Console/Commands/SendTestEmails.php index 2c1b6d1e9b0b..2d9b6d38fc15 100644 --- a/app/Console/Commands/SendTestEmails.php +++ b/app/Console/Commands/SendTestEmails.php @@ -131,7 +131,7 @@ class SendTestEmails extends Command ]); } - $invoice = InvoiceFactory::create($company->id, $user->id, $client->getMergedSettings(), $client); + $invoice = InvoiceFactory::create($company->id, $user->id); $invoice->client_id = $client->id; $invoice->setRelation('client', $client); $invoice->save(); diff --git a/app/Console/Commands/TestData/CreateTestCreditJob.php b/app/Console/Commands/TestData/CreateTestCreditJob.php new file mode 100644 index 000000000000..32a4dee4fe8c --- /dev/null +++ b/app/Console/Commands/TestData/CreateTestCreditJob.php @@ -0,0 +1,142 @@ +client = $client; + + } + + /** + * Execute the job. + * + * @return void + */ + public function handle() + { + $faker = \Faker\Factory::create(); + + $credit = factory(\App\Models\Credit::class)->create(['user_id' => $this->client->user->id, 'company_id' => $this->client->company->id, 'client_id' => $this->client->id]); + + //$invoice = InvoiceFactory::create($this->client->company->id, $this->client->user->id);//stub the company and user_id + //$invoice->client_id = $this->client->id; +// $invoice->date = $faker->date(); + $dateable = Carbon::now()->subDays(rand(0,90)); + $credit->date = $dateable; + + $credit->line_items = $this->buildLineItems(rand(1,10)); + $credit->uses_inclusive_taxes = false; + + if (rand(0, 1)) { + $credit->tax_name1 = 'GST'; + $credit->tax_rate1 = 10.00; + } + + if (rand(0, 1)) { + $credit->tax_name2 = 'VAT'; + $credit->tax_rate2 = 17.50; + } + + if (rand(0, 1)) { + $credit->tax_name3 = 'CA Sales Tax'; + $credit->tax_rate3 = 5; + } + + $credit->save(); + + $invoice_calc = new InvoiceSum($credit); + $invoice_calc->build(); + + $credit = $invoice_calc->getCredit(); + + $credit->save(); + + event(new CreateCreditInvitation($credit)); + } + + + private function buildLineItems($count = 1) + { + $line_items = []; + + for($x=0; $x<$count; $x++) + { + $item = InvoiceItemFactory::create(); + $item->quantity = 1; + //$item->cost = 10; + + if (rand(0, 1)) { + $item->tax_name1 = 'GST'; + $item->tax_rate1 = 10.00; + } + + if (rand(0, 1)) { + $item->tax_name1 = 'VAT'; + $item->tax_rate1 = 17.50; + } + + if (rand(0, 1)) { + $item->tax_name1 = 'Sales Tax'; + $item->tax_rate1 = 5; + } + + $product = Product::all()->random(); + + $item->cost = (float)$product->cost; + $item->product_key = $product->product_key; + $item->notes = $product->notes; + $item->custom_value1 = $product->custom_value1; + $item->custom_value2 = $product->custom_value2; + $item->custom_value3 = $product->custom_value3; + $item->custom_value4 = $product->custom_value4; + + + + $line_items[] = $item; + } + + return $line_items; + } +} diff --git a/app/Console/Commands/TestData/CreateTestInvoiceJob.php b/app/Console/Commands/TestData/CreateTestInvoiceJob.php new file mode 100644 index 000000000000..3fa3c4f6dca3 --- /dev/null +++ b/app/Console/Commands/TestData/CreateTestInvoiceJob.php @@ -0,0 +1,167 @@ +client = $client; + + } + + /** + * Execute the job. + * + * @return void + */ + public function handle() + { + + $faker = \Faker\Factory::create(); + + $invoice = InvoiceFactory::create($this->client->company->id, $this->client->user->id);//stub the company and user_id + $invoice->client_id = $this->client->id; +// $invoice->date = $faker->date(); + $dateable = Carbon::now()->subDays(rand(0,90)); + $invoice->date = $dateable; + + $invoice->line_items = $this->buildLineItems(rand(1,10)); + $invoice->uses_inclusive_taxes = false; + + if (rand(0, 1)) { + $invoice->tax_name1 = 'GST'; + $invoice->tax_rate1 = 10.00; + } + + if (rand(0, 1)) { + $invoice->tax_name2 = 'VAT'; + $invoice->tax_rate2 = 17.50; + } + + if (rand(0, 1)) { + $invoice->tax_name3 = 'CA Sales Tax'; + $invoice->tax_rate3 = 5; + } + + $invoice->save(); + + $invoice_calc = new InvoiceSum($invoice); + $invoice_calc->build(); + + $invoice = $invoice_calc->getInvoice(); + + $invoice->save(); + $invoice->service()->createInvitations()->markSent()->save(); + + $invoice->ledger()->updateInvoiceBalance($invoice->balance); + + //UpdateCompanyLedgerWithInvoice::dispatchNow($invoice, $invoice->balance, $invoice->company); + + //$this->invoice_repo->markSent($invoice); + + + if (rand(0, 1)) { + $payment = PaymentFactory::create($this->client->company->id, $this->client->user->id); + $payment->date = $dateable; + $payment->client_id = $this->client->id; + $payment->amount = $invoice->balance; + $payment->transaction_reference = rand(0, 500); + $payment->type_id = PaymentType::CREDIT_CARD_OTHER; + $payment->status_id = Payment::STATUS_COMPLETED; + $payment->number = $this->client->getNextPaymentNumber($this->client); + $payment->save(); + + $payment->invoices()->save($invoice); + + event(new PaymentWasCreated($payment, $payment->company)); + + $payment->service()->updateInvoicePayment(); + //UpdateInvoicePayment::dispatchNow($payment, $payment->company); + } + //@todo this slow things down, but gives us PDFs of the invoices for inspection whilst debugging. + event(new InvoiceWasCreated($invoice, $invoice->company)); + } + + + private function buildLineItems($count = 1) + { + $line_items = []; + + for($x=0; $x<$count; $x++) + { + $item = InvoiceItemFactory::create(); + $item->quantity = 1; + //$item->cost = 10; + + if (rand(0, 1)) { + $item->tax_name1 = 'GST'; + $item->tax_rate1 = 10.00; + } + + if (rand(0, 1)) { + $item->tax_name1 = 'VAT'; + $item->tax_rate1 = 17.50; + } + + if (rand(0, 1)) { + $item->tax_name1 = 'Sales Tax'; + $item->tax_rate1 = 5; + } + + $product = Product::all()->random(); + + $item->cost = (float)$product->cost; + $item->product_key = $product->product_key; + $item->notes = $product->notes; + $item->custom_value1 = $product->custom_value1; + $item->custom_value2 = $product->custom_value2; + $item->custom_value3 = $product->custom_value3; + $item->custom_value4 = $product->custom_value4; + + + + $line_items[] = $item; + } + + return $line_items; + } +} diff --git a/app/Console/Commands/TestData/CreateTestQuoteJob.php b/app/Console/Commands/TestData/CreateTestQuoteJob.php new file mode 100644 index 000000000000..1d1b834d1dae --- /dev/null +++ b/app/Console/Commands/TestData/CreateTestQuoteJob.php @@ -0,0 +1,139 @@ +client = $client; + + } + + /** + * Execute the job. + * + * @return void + */ + public function handle() + { + $faker = \Faker\Factory::create(); + + $quote =factory(\App\Models\Quote::class)->create(['user_id' => $this->client->user->id, 'company_id' => $this->client->company->id, 'client_id' => $this->client->id]); + $quote->date = $faker->date(); + + $quote->line_items = $this->buildLineItems(rand(1,10)); + $quote->uses_inclusive_taxes = false; + + if (rand(0, 1)) { + $quote->tax_name1 = 'GST'; + $quote->tax_rate1 = 10.00; + } + + if (rand(0, 1)) { + $quote->tax_name2 = 'VAT'; + $quote->tax_rate2 = 17.50; + } + + if (rand(0, 1)) { + $quote->tax_name3 = 'CA Sales Tax'; + $quote->tax_rate3 = 5; + } + + $quote->save(); + + $quote_calc = new InvoiceSum($quote); + $quote_calc->build(); + + $quote = $quote_calc->getQuote(); + $quote->service()->markSent()->save(); + + CreateQuoteInvitations::dispatch($quote, $quote->company); + + } + + + + private function buildLineItems($count = 1) + { + $line_items = []; + + for($x=0; $x<$count; $x++) + { + $item = InvoiceItemFactory::create(); + $item->quantity = 1; + //$item->cost = 10; + + if (rand(0, 1)) { + $item->tax_name1 = 'GST'; + $item->tax_rate1 = 10.00; + } + + if (rand(0, 1)) { + $item->tax_name1 = 'VAT'; + $item->tax_rate1 = 17.50; + } + + if (rand(0, 1)) { + $item->tax_name1 = 'Sales Tax'; + $item->tax_rate1 = 5; + } + + $product = Product::all()->random(); + + $item->cost = (float)$product->cost; + $item->product_key = $product->product_key; + $item->notes = $product->notes; + $item->custom_value1 = $product->custom_value1; + $item->custom_value2 = $product->custom_value2; + $item->custom_value3 = $product->custom_value3; + $item->custom_value4 = $product->custom_value4; + + + + $line_items[] = $item; + } + + return $line_items; + } + +} diff --git a/app/DataMapper/CompanySettings.php b/app/DataMapper/CompanySettings.php index e8913cb7de23..748727942408 100644 --- a/app/DataMapper/CompanySettings.php +++ b/app/DataMapper/CompanySettings.php @@ -114,6 +114,7 @@ class CompanySettings extends BaseSettings { public $enabled_item_tax_rates = 0; public $invoice_design_id = '1'; public $quote_design_id = '1'; + public $credit_design_id = '1'; public $invoice_footer = ''; public $credit_footer = ''; public $credit_terms = ''; @@ -345,6 +346,7 @@ class CompanySettings extends BaseSettings { 'phone' => 'string', 'postal_code' => 'string', 'quote_design_id' => 'string', + 'credit_design_id' => 'string', 'quote_number_pattern' => 'string', 'quote_number_counter' => 'integer', 'quote_terms' => 'string', diff --git a/app/Factory/CompanyFactory.php b/app/Factory/CompanyFactory.php index 0dfe4f4ed20e..a15cd91d6d84 100644 --- a/app/Factory/CompanyFactory.php +++ b/app/Factory/CompanyFactory.php @@ -34,6 +34,7 @@ class CompanyFactory //$company->custom_fields = (object) ['invoice1' => '1', 'invoice2' => '2', 'client1'=>'3']; $company->custom_fields = (object) []; $company->subdomain = ''; + $company->enabled_modules = 2047; return $company; } diff --git a/app/Factory/CreditFactory.php b/app/Factory/CreditFactory.php index cb2886403b3c..96fa29010ed1 100644 --- a/app/Factory/CreditFactory.php +++ b/app/Factory/CreditFactory.php @@ -24,9 +24,9 @@ class CreditFactory $credit->discount = 0; $credit->is_amount_discount = true; $credit->po_number = ''; - $credit->footer = isset($settings) && strlen($settings->credit_footer) > 0 ? $settings->credit_footer : ''; - $credit->terms = isset($settings) && strlen($settings->credit_terms) > 0 ? $settings->credit_terms : ''; - $credit->public_notes = isset($client) && strlen($client->public_notes) > 0 ? $client->public_notes : ''; + $credit->footer = ''; + $credit->terms = ''; + $credit->public_notes = ''; $credit->private_notes = ''; $credit->date = null; $credit->due_date = null; diff --git a/app/Factory/InvoiceFactory.php b/app/Factory/InvoiceFactory.php index a4fbd744d2c5..b7c7ff520a7f 100644 --- a/app/Factory/InvoiceFactory.php +++ b/app/Factory/InvoiceFactory.php @@ -19,7 +19,7 @@ use Illuminate\Support\Facades\Log; class InvoiceFactory { - public static function create(int $company_id, int $user_id, object $settings = null, Client $client = null) :Invoice + public static function create(int $company_id, int $user_id) :Invoice { $invoice = new Invoice(); $invoice->status_id = Invoice::STATUS_DRAFT; @@ -27,9 +27,9 @@ class InvoiceFactory $invoice->discount = 0; $invoice->is_amount_discount = true; $invoice->po_number = ''; - $invoice->footer = isset($settings) && strlen($settings->invoice_footer) > 0 ? $settings->invoice_footer : ''; - $invoice->terms = isset($settings) && strlen($settings->invoice_terms) > 0 ? $settings->invoice_terms : ''; - $invoice->public_notes = isset($settings) && strlen($client->public_notes) > 0 ? $client->public_notes : ''; + $invoice->footer = ''; + $invoice->terms = ''; + $invoice->public_notes = ''; $invoice->private_notes = ''; $invoice->date = null; $invoice->due_date = null; diff --git a/app/Factory/QuoteFactory.php b/app/Factory/QuoteFactory.php index e3e9d2715904..98dee2f14c4b 100644 --- a/app/Factory/QuoteFactory.php +++ b/app/Factory/QuoteFactory.php @@ -19,7 +19,7 @@ use Illuminate\Support\Facades\Log; class QuoteFactory { - public static function create(int $company_id, int $user_id, object $settings = null, Client $client = null) :Quote + public static function create(int $company_id, int $user_id) :Quote { $quote = new Quote(); $quote->status_id = Quote::STATUS_DRAFT; @@ -27,9 +27,9 @@ class QuoteFactory $quote->discount = 0; $quote->is_amount_discount = true; $quote->po_number = ''; - $quote->footer = isset($settings) && strlen($settings->quote_footer) > 0 ? $settings->quote_footer : ''; - $quote->terms = isset($settings) && strlen($settings->quote_terms) > 0 ? $settings->quote_terms : ''; - $quote->public_notes = isset($client) && strlen($client->public_notes) > 0 ? $client->public_notes : ''; + $quote->footer = ''; + $quote->terms = ''; + $quote->public_notes = ''; $quote->private_notes = ''; $quote->date = null; $quote->due_date = null; diff --git a/app/Http/Controllers/BaseController.php b/app/Http/Controllers/BaseController.php index b862284c0c1e..a79649d8043a 100644 --- a/app/Http/Controllers/BaseController.php +++ b/app/Http/Controllers/BaseController.php @@ -288,6 +288,7 @@ class BaseController extends Controller 'company.invoices', 'company.payments.paymentables', 'company.quotes', + 'company.credits', 'company.vendors.contacts', 'company.expenses', 'company.tasks', diff --git a/app/Http/Controllers/CreditController.php b/app/Http/Controllers/CreditController.php index 2263d38a78d9..2c714eb22c40 100644 --- a/app/Http/Controllers/CreditController.php +++ b/app/Http/Controllers/CreditController.php @@ -18,11 +18,17 @@ use App\Http\Requests\Credit\UpdateCreditRequest; use App\Jobs\Credit\StoreCredit; use App\Jobs\Invoice\EmailCredit; use App\Jobs\Invoice\MarkInvoicePaid; +use App\Models\Client; use App\Models\Credit; use App\Repositories\CreditRepository; use App\Transformers\CreditTransformer; use App\Utils\Traits\MakesHash; +/** + * Class CreditController + * @package App\Http\Controllers\CreditController + */ + class CreditController extends BaseController { use MakesHash; @@ -40,6 +46,48 @@ class CreditController extends BaseController $this->credit_repository = $credit_repository; } + /** + * Show the list of Credits + * + * @param \App\Filters\CreditFilters $filters The filters + * + * @return \Illuminate\Http\Response + * + * @OA\Get( + * path="/api/v1/credits", + * operationId="getCredits", + * tags={"invoices"}, + * summary="Gets a list of credits", + * description="Lists credits, search and filters allow fine grained lists to be generated. + * + * Query parameters can be added to performed more fine grained filtering of the credits, these are handled by the CreditFilters class which defines the methods available", + * @OA\Parameter(ref="#/components/parameters/X-Api-Secret"), + * @OA\Parameter(ref="#/components/parameters/X-Api-Token"), + * @OA\Parameter(ref="#/components/parameters/X-Requested-With"), + * @OA\Parameter(ref="#/components/parameters/include"), + * @OA\Response( + * response=200, + * description="A list of credits", + * @OA\Header(header="X-API-Version", ref="#/components/headers/X-API-Version"), + * @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"), + * @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"), + * @OA\JsonContent(ref="#/components/schemas/Credit"), + * ), + * @OA\Response( + * response=422, + * description="Validation error", + * @OA\JsonContent(ref="#/components/schemas/ValidationError"), + + * ), + * @OA\Response( + * response="default", + * description="Unexpected Error", + * @OA\JsonContent(ref="#/components/schemas/Error"), + * ), + * ) + * + */ + public function index(CreditFilters $filters) { $credits = Credit::filter($filters); @@ -47,6 +95,46 @@ class CreditController extends BaseController return $this->listResponse($credits); } + /** + * Show the form for creating a new resource. + * + * @param \App\Http\Requests\Credit\CreateCreditRequest $request The request + * + * @return \Illuminate\Http\Response + * + * + * @OA\Get( + * path="/api/v1/credits/create", + * operationId="getCreditsCreate", + * tags={"credits"}, + * summary="Gets a new blank credit object", + * description="Returns a blank object with default values", + * @OA\Parameter(ref="#/components/parameters/X-Api-Secret"), + * @OA\Parameter(ref="#/components/parameters/X-Api-Token"), + * @OA\Parameter(ref="#/components/parameters/X-Requested-With"), + * @OA\Parameter(ref="#/components/parameters/include"), + * @OA\Response( + * response=200, + * description="A blank credit object", + * @OA\Header(header="X-API-Version", ref="#/components/headers/X-API-Version"), + * @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"), + * @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"), + * @OA\JsonContent(ref="#/components/schemas/Credit"), + * ), + * @OA\Response( + * response=422, + * description="Validation error", + * @OA\JsonContent(ref="#/components/schemas/ValidationError"), + * + * ), + * @OA\Response( + * response="default", + * description="Unexpected Error", + * @OA\JsonContent(ref="#/components/schemas/Error"), + * ), + * ) + * + */ public function create(CreateCreditRequest $request) { $credit = CreditFactory::create(auth()->user()->company()->id, auth()->user()->id); @@ -54,9 +142,51 @@ class CreditController extends BaseController return $this->itemResponse($credit); } + /** + * Store a newly created resource in storage. + * + * @param \App\Http\Requests\Credit\StoreCreditRequest $request The request + * + * @return \Illuminate\Http\Response + * + * + * @OA\Post( + * path="/api/v1/credits", + * operationId="storeCredit", + * tags={"credits"}, + * summary="Adds a credit", + * description="Adds an credit to the system", + * @OA\Parameter(ref="#/components/parameters/X-Api-Secret"), + * @OA\Parameter(ref="#/components/parameters/X-Api-Token"), + * @OA\Parameter(ref="#/components/parameters/X-Requested-With"), + * @OA\Parameter(ref="#/components/parameters/include"), + * @OA\Response( + * response=200, + * description="Returns the saved credit object", + * @OA\Header(header="X-API-Version", ref="#/components/headers/X-API-Version"), + * @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"), + * @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"), + * @OA\JsonContent(ref="#/components/schemas/Credit"), + * ), + * @OA\Response( + * response=422, + * description="Validation error", + * @OA\JsonContent(ref="#/components/schemas/ValidationError"), + * + * ), + * @OA\Response( + * response="default", + * description="Unexpected Error", + * @OA\JsonContent(ref="#/components/schemas/Error"), + * ), + * ) + * + */ public function store(StoreCreditRequest $request) { - $credit = $this->credit_repository->save($request->all(), CreditFactory::create(auth()->user()->company()->id, auth()->user()->id)); + $client = Client::find($request->input('client_id')); + + $credit = $this->credit_repository->save($request->all(), $client->setCreditDefaults()); $credit = StoreCredit::dispatchNow($credit, $request->all(), $credit->company); @@ -65,16 +195,171 @@ class CreditController extends BaseController return $this->itemResponse($credit); } + /** + * Display the specified resource. + * + * @param \App\Http\Requests\Credit\ShowCreditRequest $request The request + * @param \App\Models\Credit $credit The credit + * + * @return \Illuminate\Http\Response + * + * + * @OA\Get( + * path="/api/v1/credits/{id}", + * operationId="showCredit", + * tags={"credits"}, + * summary="Shows an credit", + * description="Displays an credit by id", + * @OA\Parameter(ref="#/components/parameters/X-Api-Secret"), + * @OA\Parameter(ref="#/components/parameters/X-Api-Token"), + * @OA\Parameter(ref="#/components/parameters/X-Requested-With"), + * @OA\Parameter(ref="#/components/parameters/include"), + * @OA\Parameter( + * name="id", + * in="path", + * description="The Credit Hashed ID", + * example="D2J234DFA", + * required=true, + * @OA\Schema( + * type="string", + * format="string", + * ), + * ), + * @OA\Response( + * response=200, + * description="Returns the credit object", + * @OA\Header(header="X-API-Version", ref="#/components/headers/X-API-Version"), + * @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"), + * @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"), + * @OA\JsonContent(ref="#/components/schemas/Credit"), + * ), + * @OA\Response( + * response=422, + * description="Validation error", + * @OA\JsonContent(ref="#/components/schemas/ValidationError"), + * + * ), + * @OA\Response( + * response="default", + * description="Unexpected Error", + * @OA\JsonContent(ref="#/components/schemas/Error"), + * ), + * ) + * + */ public function show(ShowCreditRequest $request, Credit $credit) { return $this->itemResponse($credit); } + /** + * Show the form for editing the specified resource. + * + * @param \App\Http\Requests\Invoice\EditInvoiceRequest $request The request + * @param \App\Models\Invoice $credit The credit + * + * @return \Illuminate\Http\Response + * + * @OA\Get( + * path="/api/v1/credits/{id}/edit", + * operationId="editInvoice", + * tags={"credits"}, + * summary="Shows an credit for editting", + * description="Displays an credit by id", + * @OA\Parameter(ref="#/components/parameters/X-Api-Secret"), + * @OA\Parameter(ref="#/components/parameters/X-Api-Token"), + * @OA\Parameter(ref="#/components/parameters/X-Requested-With"), + * @OA\Parameter(ref="#/components/parameters/include"), + * @OA\Parameter( + * name="id", + * in="path", + * description="The Invoice Hashed ID", + * example="D2J234DFA", + * required=true, + * @OA\Schema( + * type="string", + * format="string", + * ), + * ), + * @OA\Response( + * response=200, + * description="Returns the credit object", + * @OA\Header(header="X-API-Version", ref="#/components/headers/X-API-Version"), + * @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"), + * @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"), + * @OA\JsonContent(ref="#/components/schemas/Invoice"), + * ), + * @OA\Response( + * response=422, + * description="Validation error", + * @OA\JsonContent(ref="#/components/schemas/ValidationError"), + * + * ), + * @OA\Response( + * response="default", + * description="Unexpected Error", + * @OA\JsonContent(ref="#/components/schemas/Error"), + * ), + * ) + * + */ public function edit(EditCreditRequest $request, Credit $credit) { return $this->itemResponse($credit); } + /** + * Update the specified resource in storage. + * + * @param \App\Http\Requests\Credit\UpdateCreditRequest $request The request + * @param \App\Models\Credit $Credit The Credit + * + * @return \Illuminate\Http\Response + * + * + * @OA\Put( + * path="/api/v1/Credits/{id}", + * operationId="updateCredit", + * tags={"Credits"}, + * summary="Updates an Credit", + * description="Handles the updating of an Credit by id", + * @OA\Parameter(ref="#/components/parameters/X-Api-Secret"), + * @OA\Parameter(ref="#/components/parameters/X-Api-Token"), + * @OA\Parameter(ref="#/components/parameters/X-Requested-With"), + * @OA\Parameter(ref="#/components/parameters/include"), + * @OA\Parameter( + * name="id", + * in="path", + * description="The Credit Hashed ID", + * example="D2J234DFA", + * required=true, + * @OA\Schema( + * type="string", + * format="string", + * ), + * ), + * @OA\Response( + * response=200, + * description="Returns the Credit object", + * @OA\Header(header="X-API-Version", ref="#/components/headers/X-API-Version"), + * @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"), + * @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"), + * @OA\JsonContent(ref="#/components/schemas/Credit"), + * ), + * @OA\Response( + * response=422, + * description="Validation error", + * @OA\JsonContent(ref="#/components/schemas/ValidationError"), + * + * ), + * @OA\Response( + * response="default", + * description="Unexpected Error", + * @OA\JsonContent(ref="#/components/schemas/Error"), + * ), + * ) + * + */ public function update(UpdateCreditRequest $request, Credit $credit) { if($request->entityIsDeleted($credit)) @@ -87,6 +372,56 @@ class CreditController extends BaseController return $this->itemResponse($credit); } + /** + * Remove the specified resource from storage. + * + * @param \App\Http\Requests\Credit\DestroyCreditRequest $request + * @param \App\Models\Credit $credit + * + * @return \Illuminate\Http\Response + * + * @OA\Delete( + * path="/api/v1/credits/{id}", + * operationId="deleteCredit", + * tags={"credits"}, + * summary="Deletes a credit", + * description="Handles the deletion of an credit by id", + * @OA\Parameter(ref="#/components/parameters/X-Api-Secret"), + * @OA\Parameter(ref="#/components/parameters/X-Api-Token"), + * @OA\Parameter(ref="#/components/parameters/X-Requested-With"), + * @OA\Parameter(ref="#/components/parameters/include"), + * @OA\Parameter( + * name="id", + * in="path", + * description="The Credit Hashed ID", + * example="D2J234DFA", + * required=true, + * @OA\Schema( + * type="string", + * format="string", + * ), + * ), + * @OA\Response( + * response=200, + * description="Returns a HTTP status", + * @OA\Header(header="X-API-Version", ref="#/components/headers/X-API-Version"), + * @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"), + * @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"), + * ), + * @OA\Response( + * response=422, + * description="Validation error", + * @OA\JsonContent(ref="#/components/schemas/ValidationError"), + * + * ), + * @OA\Response( + * response="default", + * description="Unexpected Error", + * @OA\JsonContent(ref="#/components/schemas/Error"), + * ), + * ) + * + */ public function destroy(DestroyCreditRequest $request, Credit $credit) { $credit->delete(); @@ -94,6 +429,57 @@ class CreditController extends BaseController return response()->json([], 200); } + /** + * Perform bulk actions on the list view + * + * @return Collection + * + * @OA\Post( + * path="/api/v1/credits/bulk", + * operationId="bulkCredits", + * tags={"credits"}, + * summary="Performs bulk actions on an array of credits", + * description="", + * @OA\Parameter(ref="#/components/parameters/X-Api-Secret"), + * @OA\Parameter(ref="#/components/parameters/X-Api-Token"), + * @OA\Parameter(ref="#/components/parameters/X-Requested-With"), + * @OA\Parameter(ref="#/components/parameters/index"), + * @OA\RequestBody( + * description="User credentials", + * required=true, + * @OA\MediaType( + * mediaType="application/json", + * @OA\Schema( + * type="array", + * @OA\Items( + * type="integer", + * description="Array of hashed IDs to be bulk 'actioned", + * example="[0,1,2,3]", + * ), + * ) + * ) + * ), + * @OA\Response( + * response=200, + * description="The Bulk Action response", + * @OA\Header(header="X-API-Version", ref="#/components/headers/X-API-Version"), + * @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"), + * @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"), + * ), + * @OA\Response( + * response=422, + * description="Validation error", + * @OA\JsonContent(ref="#/components/schemas/ValidationError"), + + * ), + * @OA\Response( + * response="default", + * description="Unexpected Error", + * @OA\JsonContent(ref="#/components/schemas/Error"), + * ), + * ) + * + */ public function bulk() { $action = request()->input('action'); @@ -150,7 +536,7 @@ class CreditController extends BaseController } break; case 'mark_sent': - $credit->markSent(); + $credit->service()->markSent()->save(); if (!$bulk) { return $this->itemResponse($credit); diff --git a/app/Http/Controllers/InvoiceController.php b/app/Http/Controllers/InvoiceController.php index 0917c487e7ec..815a63977689 100644 --- a/app/Http/Controllers/InvoiceController.php +++ b/app/Http/Controllers/InvoiceController.php @@ -159,7 +159,7 @@ class InvoiceController extends BaseController { */ public function create(CreateInvoiceRequest $request) { - $invoice = InvoiceFactory::create(auth()->user()->company()->id, auth()->user()->id, $client->getMergedSettings(), $client); + $invoice = InvoiceFactory::create(auth()->user()->company()->id, auth()->user()->id); return $this->itemResponse($invoice); } @@ -208,7 +208,7 @@ class InvoiceController extends BaseController { $client = Client::find($request->input('client_id')); - $invoice = $this->invoice_repo->save($request->all(), InvoiceFactory::create(auth()->user()->company()->id, auth()->user()->id), $client->getMergedSettings(), $client); + $invoice = $this->invoice_repo->save($request->all(), $client->setInvoiceDefaults()); $invoice = StoreInvoice::dispatchNow($invoice, $request->all(), $invoice->company);//todo potentially this may return mixed ie PDF/$invoice... need to revisit when we implement UI @@ -514,6 +514,10 @@ class InvoiceController extends BaseController { return response()->json(['message' => 'No Invoices Found']); } + /* + * Download Invoice/s + */ + if($action == 'download' && $invoices->count() > 1) { @@ -530,7 +534,9 @@ class InvoiceController extends BaseController { return response()->json(['message' => 'Email Sent!'],200); } - + /* + * Send the other actions to the switch + */ $invoices->each(function ($invoice, $key) use ($action) { if (auth()->user()->can('edit', $invoice)) { diff --git a/app/Http/Controllers/OpenAPI/CreditSchema.php b/app/Http/Controllers/OpenAPI/CreditSchema.php new file mode 100644 index 000000000000..3917f7faa1dc --- /dev/null +++ b/app/Http/Controllers/OpenAPI/CreditSchema.php @@ -0,0 +1,53 @@ +quote_repo->save($request->all(), QuoteFactory::create(auth()->user()->company()->id, auth()->user()->id)); + $client = Client::find($request->input('client_id')); + + $quote = $this->quote_repo->save($request->all(), $client->setQuoteDefaults()); return $this->itemResponse($quote); } @@ -495,20 +499,55 @@ class QuoteController extends BaseController */ public function bulk() { + /* + * WIP! + */ $action = request()->input('action'); - + $ids = request()->input('ids'); - $quotes = Quote::withTrashed()->find($this->transformKeys($ids)); + $quotes = Quote::withTrashed()->whereIn('id', $this->transformKeys($ids))->company()->get(); + if (!$quotes) { + return response()->json(['message' => 'No Quotes Found']); + } + + /* + * Download Invoice/s + */ + + if($action == 'download' && $quotes->count() > 1) + { + + $quotes->each(function ($quote) { + + if(auth()->user()->cannot('view', $quote)){ + return response()->json(['message'=>'Insufficient privileges to access quote '. $quote->number]); + } + + }); + + ZipInvoices::dispatch($quotes, $quotes->first()->company, auth()->user()->email); + + return response()->json(['message' => 'Email Sent!'],200); + } + + /* + * Send the other actions to the switch + */ $quotes->each(function ($quote, $key) use ($action) { + if (auth()->user()->can('edit', $quote)) { - $this->quote_repo->{$action}($quote); + $this->performAction($quote, $action, true); } + }); - return $this->listResponse(Quote::withTrashed()->whereIn('id', $this->transformKeys($ids))); + /* Need to understand which permission are required for the given bulk action ie. view / edit */ + + return $this->listResponse(Quote::withTrashed()->whereIn('id', $this->transformKeys($ids))->company()); } + /** * Quote Actions @@ -580,13 +619,19 @@ class QuoteController extends BaseController * ) * */ - public function action(ActionQuoteRequest $request, Quote $quote, $action) + + public function action(ActionQuoteRequest $request, Quote $quote, $action) { + return $this->performAction($quote, $action); + } + + + private function performAction(Quote $quote, $action, $bulk = false) { switch ($action) { case 'clone_to_invoice': - $this->entity_type = Invoice::class; - $this->entity_transformer = InvoiceTransformer::class; + $this->entity_type = Quote::class; + $this->entity_transformer = QuoteTransformer::class; $invoice = CloneQuoteToInvoiceFactory::create($quote, auth()->user()->id); return $this->itemResponse($invoice); @@ -618,9 +663,16 @@ class QuoteController extends BaseController case 'email': return response()->json(['message'=>'email sent'], 200); break; + case 'mark_sent': + $quote->service()->markSent()->save(); + + if (!$bulk) { + return $this->itemResponse($quote); + } default: return response()->json(['message' => "The requested action `{$action}` is not available."], 400); break; } } + } diff --git a/app/Http/Requests/Client/StoreClientRequest.php b/app/Http/Requests/Client/StoreClientRequest.php index bf05d4b8f78a..0fb8412dc86a 100644 --- a/app/Http/Requests/Client/StoreClientRequest.php +++ b/app/Http/Requests/Client/StoreClientRequest.php @@ -15,6 +15,7 @@ use App\DataMapper\ClientSettings; use App\Http\Requests\Request; use App\Http\ValidationRules\ValidClientGroupSettingsRule; use App\Models\Client; +use App\Models\GroupSetting; use App\Utils\Traits\MakesHash; use Illuminate\Validation\Rule; @@ -80,6 +81,23 @@ class StoreClientRequest extends Request $input['group_settings_id'] = $this->decodePrimaryKey($input['group_settings_id']); } + if(empty($input['settings']->currency_id)) + { + if(empty($input['group_settings_id'])) + { + $input['settings']->currency_id = auth()->user()->company()->settings->currency_id; + } + else + { + $group_settings = GroupSetting::find($input['group_settings_id']); + + if($group_settings && property_exists($group_settings, 'currency_id') && is_int($group_settings->currency_id)) + $input['settings']->currency_id = $group_settings->currency_id; + else + $input['settings']->currency_id = auth()->user()->company()->settings->currency_id; + } + } + if(isset($input['contacts'])) { foreach($input['contacts'] as $key => $contact) diff --git a/app/Http/Requests/Company/StoreCompanyRequest.php b/app/Http/Requests/Company/StoreCompanyRequest.php index e9f2b92a0c17..23298ef4cd2f 100644 --- a/app/Http/Requests/Company/StoreCompanyRequest.php +++ b/app/Http/Requests/Company/StoreCompanyRequest.php @@ -56,6 +56,8 @@ class StoreCompanyRequest extends Request $input['settings']['pdf_variables'] = CompanySettings::getEntityVariableDefaults(); } + + $this->replace($input); } } diff --git a/app/Jobs/Account/CreateAccount.php b/app/Jobs/Account/CreateAccount.php index 2dd37b6c1f94..0a80bab18bee 100644 --- a/app/Jobs/Account/CreateAccount.php +++ b/app/Jobs/Account/CreateAccount.php @@ -17,7 +17,7 @@ use App\Jobs\Company\CreateCompanyToken; use App\Jobs\User\CreateUser; use App\Models\Account; use App\Models\User; -use App\Notifications\NewAccountCreated; +use App\Notifications\Ninja\NewAccountCreated; use App\Utils\Traits\UserSessionAttributes; use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Http\Request; @@ -92,14 +92,7 @@ class CreateAccount $user->fresh(); - $company->notification(new NewAccountCreated($user, $company))->run(); - - // $user->route('slack', $company->settings->system_notifications_slack) - // ->route('mail', $company->settings->system_notifications_email) - // ->notify(new NewAccountCreated($user, $company)); - - // Notification::route('slack', config('ninja.notification.slack')) - // ->notify(new NewAccountCreated($user, $company)); + $company->notification(new NewAccountCreated($user, $company))->ninja(); return $account; } diff --git a/app/Jobs/Credit/CreateCreditPdf.php b/app/Jobs/Credit/CreateCreditPdf.php new file mode 100644 index 000000000000..73e17ab742c5 --- /dev/null +++ b/app/Jobs/Credit/CreateCreditPdf.php @@ -0,0 +1,107 @@ +credit = $credit; + + $this->company = $company; + + $this->contact = $contact; + + $this->disk = $disk ?? config('filesystems.default'); + + } + + public function handle() { + + MultiDB::setDB($this->company->db); + + $this->credit->load('client'); + + if(!$this->contact) + $this->contact = $this->credit->client->primary_contact()->first(); + + App::setLocale($this->contact->preferredLocale()); + + $path = $this->credit->client->credit_filepath(); + + $file_path = $path . $this->credit->number . '.pdf'; + + $design = Design::find($this->credit->client->getSetting('credit_design_id')); + + if($design->is_custom){ + $credit_design = new Custom($design->design); + } + else{ + $class = 'App\Designs\\'.$design->name; + $credit_design = new $class(); + } + + $designer = new Designer($credit_design, $this->credit->client->getSetting('pdf_variables'), 'credit'); + + //get invoice design + $html = $this->generateInvoiceHtml($designer->build($this->credit)->getHtml(), $this->credit, $this->contact); + + //todo - move this to the client creation stage so we don't keep hitting this unnecessarily + Storage::makeDirectory($path, 0755); + + //\Log::error($html); + $pdf = $this->makePdf(null, null, $html); + + $instance = Storage::disk($this->disk)->put($file_path, $pdf); + + //$instance= Storage::disk($this->disk)->path($file_path); + // + return $file_path; + } + +} diff --git a/app/Listeners/Payment/PaymentNotification.php b/app/Listeners/Payment/PaymentNotification.php index 2f2ac27cfec8..8d906d5fc7ee 100644 --- a/app/Listeners/Payment/PaymentNotification.php +++ b/app/Listeners/Payment/PaymentNotification.php @@ -18,6 +18,7 @@ use App\Notifications\Payment\NewPaymentNotification; use App\Repositories\ActivityRepository; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Queue\InteractsWithQueue; +use Illuminate\Support\Facades\Notification; class PaymentNotification implements ShouldQueue { @@ -46,5 +47,12 @@ class PaymentNotification implements ShouldQueue { $company_user->user->notify(new NewPaymentNotification($payment, $payment->company)); } + + if(isset($payment->company->slack_webhook_url)){ + + Notification::route('slack', $payment->company->slack_webhook_url) + ->notify(new NewPaymentNotification($payment, $payment->company, true)); + + } } } diff --git a/app/Models/Client.php b/app/Models/Client.php index 7a2191383e11..3e09ccb36b8c 100644 --- a/app/Models/Client.php +++ b/app/Models/Client.php @@ -13,17 +13,23 @@ namespace App\Models; use App\DataMapper\ClientSettings; use App\DataMapper\CompanySettings; +use App\Factory\CreditFactory; +use App\Factory\InvoiceFactory; +use App\Factory\QuoteFactory; use App\Models\Client; use App\Models\Company; use App\Models\CompanyGateway; use App\Models\Country; +use App\Models\Credit; use App\Models\Currency; use App\Models\DateFormat; use App\Models\DatetimeFormat; use App\Models\Filterable; use App\Models\GatewayType; use App\Models\GroupSetting; +use App\Models\Invoice; use App\Models\Language; +use App\Models\Quote; use App\Models\Timezone; use App\Models\User; use App\Services\Client\ClientService; @@ -454,4 +460,31 @@ class Client extends BaseModel implements HasLocalePreference { return $this->client_hash . '/credits/'; } + + public function setInvoiceDefaults() :Invoice + { + $invoice_factory = InvoiceFactory::create($this->company_id, auth()->user()->id); + $invoice_factory->terms = $this->getSetting('invoice_terms'); + $invoice_factory->footer = $this->getSetting('invoice_footer'); + $invoice_factory->public_notes = isset($this->public_notes) ? $this->public_notes : ''; + return $invoice_factory; + } + + public function setQuoteDefaults() :Quote + { + $quote_factory = QuoteFactory::create($this->company_id, auth()->user()->id); + $quote_factory->terms = $this->getSetting('quote_terms'); + $quote_factory->footer = $this->getSetting('quote_footer'); + $quote_factory->public_notes = isset($this->public_notes) ? $this->public_notes : ''; + return $quote_factory; + } + + public function setCreditDefaults() :Credit + { + $credit_factory = CreditFactory::create($this->company_id, auth()->user()->id); + $credit_factory->terms = $this->getSetting('credit_terms'); + $credit_factory->footer = $this->getSetting('credit_footer'); + $credit_factory->public_notes = isset($this->public_notes) ? $this->public_notes : ''; + return $credit_factory; + } } diff --git a/app/Models/Company.php b/app/Models/Company.php index 7b75de666065..ecf1e9488120 100644 --- a/app/Models/Company.php +++ b/app/Models/Company.php @@ -51,6 +51,18 @@ class Company extends BaseModel use \Staudenmeir\EloquentHasManyDeep\HasRelationships; use \Staudenmeir\EloquentHasManyDeep\HasTableAlias; + const ENTITY_RECURRING_INVOICE = 'recurring_invoice'; + const ENTITY_CREDIT = 'credit'; + const ENTITY_QUOTE = 'quote'; + const ENTITY_TASK = 'task'; + const ENTITY_EXPENSE = 'expense'; + const ENTITY_PROJECT = 'project'; + const ENTITY_VENDOR = 'vendor'; + const ENTITY_TICKET = 'ticket'; + const ENTITY_PROPOSAL = 'proposal'; + const ENTITY_RECURRING_EXPENSE = 'expense'; + const ENTITY_RECURRING_TASK = 'task'; + protected $presenter = 'App\Models\Presenters\CompanyPresenter'; protected $fillable = [ @@ -100,6 +112,20 @@ class Company extends BaseModel // 'tokens' ]; + public static $modules = [ + self::ENTITY_RECURRING_INVOICE => 1, + self::ENTITY_CREDIT => 2, + self::ENTITY_QUOTE => 4, + self::ENTITY_TASK => 8, + self::ENTITY_EXPENSE => 16, + self::ENTITY_PROJECT => 32, + self::ENTITY_VENDOR => 64, + self::ENTITY_TICKET => 128, + self::ENTITY_PROPOSAL => 256, + self::ENTITY_RECURRING_EXPENSE => 512, + self::ENTITY_RECURRING_TASK => 1024, + ]; + public function getCompanyIdAttribute() { return $this->encodePrimaryKey($this->id); @@ -337,9 +363,8 @@ class Company extends BaseModel { //todo need to return the company channel here for hosted users //else the env variable for selfhosted - if(config('ninja.environment') == 'selfhosted') - return config('ninja.notification.slack'); - else - return $this->settings->system_notifications_slack; + // + return $this->slack_webhook_url; + } } diff --git a/app/Models/Credit.php b/app/Models/Credit.php index a4c7e180d634..c4ac741557c1 100644 --- a/app/Models/Credit.php +++ b/app/Models/Credit.php @@ -13,12 +13,14 @@ namespace App\Models; use App\Helpers\Invoice\InvoiceSum; use App\Helpers\Invoice\InvoiceSumInclusive; +use App\Jobs\Credit\CreateCreditPdf; use App\Models\Filterable; use App\Services\Credit\CreditService; use App\Utils\Traits\MakesDates; use App\Utils\Traits\MakesHash; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\SoftDeletes; +use Illuminate\Support\Carbon; class Credit extends BaseModel { @@ -64,8 +66,9 @@ class Credit extends BaseModel ]; const STATUS_DRAFT = 1; - const STAUS_PARTIAL = 2; - const STATUS_APPLIED = 3; + const STATUS_SENT = 2; + const STATUS_PARTIAL = 3; + const STATUS_APPLIED = 4; public function assigned_user() { @@ -172,5 +175,31 @@ class Credit extends BaseModel $this->status_id = $status; $this->save(); } + + public function pdf_file_path($invitation = null) + { + $storage_path = 'storage/' . $this->client->credit_filepath() . $this->number . '.pdf'; + + if (Storage::exists($storage_path)) + return $storage_path; + + if(!$invitation) + CreateCreditPdf::dispatchNow($this, $this->company, $this->client->primary_contact()->first()); + else + CreateCreditPdf::dispatchNow($invitation->credit, $invitation->company, $invitation->contact); + + return $storage_path; + + } + + public function markInvitationsSent() + { + $this->invitations->each(function ($invitation) { + if (!isset($invitation->sent_date)) { + $invitation->sent_date = Carbon::now(); + $invitation->save(); + } + }); + } } diff --git a/app/Models/Quote.php b/app/Models/Quote.php index 86633ecc9d11..3b54e4721212 100644 --- a/app/Models/Quote.php +++ b/app/Models/Quote.php @@ -22,6 +22,7 @@ use App\Utils\Traits\MakesInvoiceValues; use App\Utils\Traits\MakesReminders; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\SoftDeletes; +use Illuminate\Support\Carbon; use Illuminate\Support\Facades\Storage; use Laracasts\Presenter\PresentableTrait; diff --git a/app/Models/User.php b/app/Models/User.php index e7106aeb2c14..ea50234eca1a 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -303,7 +303,6 @@ class User extends Authenticatable implements MustVerifyEmail if($this->company()) return $this->company()->slack_webhook_url; - } diff --git a/app/Notifications/NewAccountCreated.php b/app/Notifications/NewAccountCreated.php index 38718b1c6fd8..e8d227081dc8 100644 --- a/app/Notifications/NewAccountCreated.php +++ b/app/Notifications/NewAccountCreated.php @@ -23,10 +23,13 @@ class NewAccountCreated extends Notification implements ShouldQueue protected $company; - public function __construct($user, $company) + public $is_system; + + public function __construct($user, $company, $is_system = false) { $this->user = $user; $this->company = $company; + $this->is_system = $is_system; } /** @@ -37,7 +40,6 @@ class NewAccountCreated extends Notification implements ShouldQueue */ public function via($notifiable) { - //return ['mail']; return ['slack','mail']; } @@ -95,8 +97,7 @@ class NewAccountCreated extends Notification implements ShouldQueue return (new SlackMessage) ->success() - ->to("#devv2") - ->from("System") + ->from(ctrans('texts.notification_bot')) ->image('https://app.invoiceninja.com/favicon.png') ->content("A new account has been created by {$user_name} - {$email} - from IP: {$ip}"); } diff --git a/app/Notifications/Ninja/InvoiceViewedNotification.php b/app/Notifications/Ninja/InvoiceViewedNotification.php new file mode 100644 index 000000000000..dc1d1c2488dd --- /dev/null +++ b/app/Notifications/Ninja/InvoiceViewedNotification.php @@ -0,0 +1,123 @@ +invoice = $invitation->invoice; + $this->contact = $invitation->contact; + $this->company = $company; + $this->settings = $invoice->client->getMergedSettings(); + $this->is_system = $is_system; + } + + /** + * Get the notification's delivery channels. + * + * @param mixed $notifiable + * @return array + */ + public function via($notifiable) + { + + return $this->is_system ? ['slack'] : ['mail']; + } + + /** + * Get the mail representation of the notification. + * + * @param mixed $notifiable + * @return \Illuminate\Notifications\Messages\MailMessage + */ + public function toMail($notifiable) + { + + $amount = Number::formatMoney($this->invoice->amount, $this->invoice->client); + $subject = ctrans('texts.notification_invoice_viewed_subject', + [ + 'client' => $this->contact->present()->name(), + 'invoice' => $this->invoice->number, + ]); + + $data = [ + 'title' => $subject, + 'message' => ctrans('texts.notification_invoice_viewed', + [ + 'amount' => $amount, + 'client' => $this->contact->present()->name(), + 'invoice' => $this->invoice->number, + ]), + 'url' => config('ninja.site_url') . '/invoices/' . $this->invoice->hashed_id, + 'button' => ctrans('texts.view_invoice'), + 'signature' => $this->settings->email_signature, + 'logo' => $this->company->present()->logo(), + ]; + + + return (new MailMessage) + ->subject($subject) + ->markdown('email.admin.generic', $data); + + + } + + /** + * Get the array representation of the notification. + * + * @param mixed $notifiable + * @return array + */ + public function toArray($notifiable) + { + return [ + // + ]; + } + + public function toSlack($notifiable) + { + $logo = $this->company->present()->logo(); + $amount = Number::formatMoney($this->invoice->amount, $this->invoice->client); + + return (new SlackMessage) + ->success() + ->from(ctrans('texts.notification_bot')) + ->image($logo) + ->content(ctrans('texts.notification_invoice_viewed', + [ + 'amount' => $amount, + 'client' => $this->contact->present()->name(), + 'invoice' => $this->invoice->number, + ]); + } + +} diff --git a/app/Notifications/Ninja/NewAccountCreated.php b/app/Notifications/Ninja/NewAccountCreated.php new file mode 100644 index 000000000000..37101ae81762 --- /dev/null +++ b/app/Notifications/Ninja/NewAccountCreated.php @@ -0,0 +1,104 @@ +user = $user; + $this->company = $company; + $this->is_system = $is_system; + } + + /** + * Get the notification's delivery channels. + * + * @param mixed $notifiable + * @return array + */ + public function via($notifiable) + { + return ['slack','mail']; + } + + /** + * Get the mail representation of the notification. + * + * @param mixed $notifiable + * @return \Illuminate\Notifications\Messages\MailMessage + */ + public function toMail($notifiable) + { + + $user_name = $this->user->first_name . " " . $this->user->last_name; + $email = $this->user->email; + $ip = $this->user->ip; + + $data = [ + 'title' => ctrans('texts.new_signup'), + 'message' => ctrans('texts.new_signup_text', ['user' => $user_name, 'email' => $email, 'ip' => $ip]), + 'url' => config('ninja.web_url'), + 'button' => ctrans('texts.account_login'), + 'signature' => $this->company->settings->email_signature, + 'logo' => $this->company->present()->logo(), + ]; + + + return (new MailMessage) + ->subject(ctrans('texts.new_signup')) + ->markdown('email.admin.generic', $data); + + + } + + /** + * Get the array representation of the notification. + * + * @param mixed $notifiable + * @return array + */ + public function toArray($notifiable) + { + return [ + // + ]; + } + + public function toSlack($notifiable) + { + + $this->user->setCompany($this->company); + + $user_name = $this->user->first_name . " " . $this->user->last_name; + $email = $this->user->email; + $ip = $this->user->ip; + + return (new SlackMessage) + ->success() + ->from(ctrans('texts.notification_bot')) + ->image('https://app.invoiceninja.com/favicon.png') + ->content("A new account has been created by {$user_name} - {$email} - from IP: {$ip}"); + } +} diff --git a/app/Notifications/Payment/NewPartialPaymentNotification.php b/app/Notifications/Payment/NewPartialPaymentNotification.php new file mode 100644 index 000000000000..e1d303eac83a --- /dev/null +++ b/app/Notifications/Payment/NewPartialPaymentNotification.php @@ -0,0 +1,126 @@ +payment = $payment; + $this->company = $company; + $this->settings = $payment->client->getMergedSettings(); + $this->is_system = $is_system; + } + + /** + * Get the notification's delivery channels. + * + * @param mixed $notifiable + * @return array + */ + public function via($notifiable) + { + + return $this->is_system ? ['slack'] : ['mail']; + } + + /** + * Get the mail representation of the notification. + * + * @param mixed $notifiable + * @return \Illuminate\Notifications\Messages\MailMessage + */ + public function toMail($notifiable) + { + $amount = Number::formatMoney($this->payment->amount, $this->payment->client); + + $invoice_texts = ctrans('texts.invoice_number_short'); + + foreach($this->payment->invoices as $invoice) + $invoice_texts .= $invoice->number . ','; + + $invoice_texts = substr($invoice_texts, 0, -1); + + $data = [ + 'title' => ctrans('texts.notification_partial_payment_paid_subject', + ['client' => $this->payment->client->present()->name()]), + 'message' => ctrans('texts.notification_partial_payment_paid', + ['amount' => $amount, + 'client' => $this->payment->client->present()->name(), + 'invoice' => $invoice_texts, + ]), + 'url' => config('ninja.site_url') . '/payments/' . $this->payment->hashed_id, + 'button' => ctrans('texts.view_payment'), + 'signature' => $this->settings->email_signature, + 'logo' => $this->company->present()->logo(), + ]; + + + return (new MailMessage) + ->subject(ctrans('texts.notification_partial_payment_paid_subject', + ['client' => $this->payment->client->present()->name()]) + )->markdown('email.admin.generic', $data); + + + } + + /** + * Get the array representation of the notification. + * + * @param mixed $notifiable + * @return array + */ + public function toArray($notifiable) + { + return [ + // + ]; + } + + public function toSlack($notifiable) + { + $logo = $this->company->present()->logo(); + $amount = Number::formatMoney($this->payment->amount, $this->payment->client); + $invoice_texts = ctrans('texts.invoice_number_short'); + + foreach($this->payment->invoices as $invoice) + $invoice_texts .= $invoice->number . ','; + + $invoice_texts = substr($invoice_texts, 0, -1); + + return (new SlackMessage) + ->success() + //->to("#devv2") + ->from("System") + ->image($logo) + ->content(ctrans('texts.notification_payment_paid', + ['amount' => $amount, + 'client' => $this->payment->client->present()->name(), + 'invoice' => $invoice_texts])); + } + +} diff --git a/app/Notifications/Payment/NewPaymentNotification.php b/app/Notifications/Payment/NewPaymentNotification.php index cf61ca3676af..6ea89f8c345c 100644 --- a/app/Notifications/Payment/NewPaymentNotification.php +++ b/app/Notifications/Payment/NewPaymentNotification.php @@ -26,11 +26,14 @@ class NewPaymentNotification extends Notification implements ShouldQueue protected $settings; - public function __construct($payment, $company, $settings = null) + protected $is_system; + + public function __construct($payment, $company, $is_system = false, $settings = null) { $this->payment = $payment; $this->company = $company; $this->settings = $payment->client->getMergedSettings(); + $this->is_system = $is_system; } /** @@ -41,8 +44,8 @@ class NewPaymentNotification extends Notification implements ShouldQueue */ public function via($notifiable) { - //return ['mail']; - return ['mail']; + + return $this->is_system ? ['slack'] : ['mail']; } /** @@ -58,25 +61,29 @@ class NewPaymentNotification extends Notification implements ShouldQueue $invoice_texts = ctrans('texts.invoice_number_short'); foreach($this->payment->invoices as $invoice) - { $invoice_texts .= $invoice->number . ','; - } - $invoice_texts = rtrim($invoice_texts); + $invoice_texts = substr($invoice_texts, 0, -1); $data = [ - 'title' => ctrans('texts.notification_payment_paid_subject', ['client' => $this->payment->client->present()->name()]), - 'message' => ctrans('texts.notification_paid_paid', ['amount' => $amount, 'client' => $this->payment->client->present()->name(), 'invoice' => $invoice_texts]), + 'title' => ctrans('texts.notification_payment_paid_subject', + ['client' => $this->payment->client->present()->name()]), + 'message' => ctrans('texts.notification_payment_paid', + ['amount' => $amount, + 'client' => $this->payment->client->present()->name(), + 'invoice' => $invoice_texts, + ]), 'url' => config('ninja.site_url') . '/payments/' . $this->payment->hashed_id, 'button' => ctrans('texts.view_payment'), - 'signature' => $this->company->settings->email_signature, + 'signature' => $this->settings->email_signature, 'logo' => $this->company->present()->logo(), ]; return (new MailMessage) - ->subject(ctrans('texts.notification_payment_paid_subject', ['client' => $this->payment->client->present()->name()])) - ->markdown('email.admin.generic', $data); + ->subject(ctrans('texts.notification_payment_paid_subject', + ['client' => $this->payment->client->present()->name(),]) + )->markdown('email.admin.generic', $data); } @@ -97,13 +104,23 @@ class NewPaymentNotification extends Notification implements ShouldQueue public function toSlack($notifiable) { $logo = $this->company->present()->logo(); + $amount = Number::formatMoney($this->payment->amount, $this->payment->client); + $invoice_texts = ctrans('texts.invoice_number_short'); + + foreach($this->payment->invoices as $invoice) + $invoice_texts .= $invoice->number . ','; + + $invoice_texts = substr($invoice_texts, 0, -1); return (new SlackMessage) ->success() - ->to("#devv2") + //->to("#devv2") ->from("System") ->image($logo) - ->content("A new account has been created by {$user_name} - {$email} - from IP: {$ip}"); + ->content(ctrans('texts.notification_payment_paid', + ['amount' => $amount, + 'client' => $this->payment->client->present()->name(), + 'invoice' => $invoice_texts])); } } diff --git a/app/Providers/EventServiceProvider.php b/app/Providers/EventServiceProvider.php index bba9838c999e..20ff149b82dc 100644 --- a/app/Providers/EventServiceProvider.php +++ b/app/Providers/EventServiceProvider.php @@ -13,6 +13,7 @@ namespace App\Providers; use App\Events\Client\ClientWasCreated; use App\Events\Contact\ContactLoggedIn; +use App\Events\Credit\CreditWasMarkedSent; use App\Events\Invoice\InvoiceWasCreated; use App\Events\Invoice\InvoiceWasEmailed; use App\Events\Invoice\InvoiceWasMarkedSent; @@ -100,8 +101,10 @@ class EventServiceProvider extends ServiceProvider 'App\Listeners\ActivityListener@restoredClient', ], - //Invoices + CreditWasMarkedSent::class => [ + ], + //Invoices InvoiceWasMarkedSent::class => [ CreateInvoiceHtmlBackup::class, ], diff --git a/app/Providers/MultiDBProvider.php b/app/Providers/MultiDBProvider.php index d144b5ab1011..9ab4fc41532e 100644 --- a/app/Providers/MultiDBProvider.php +++ b/app/Providers/MultiDBProvider.php @@ -23,7 +23,6 @@ class MultiDBProvider extends ServiceProvider */ public function boot() { - } /** @@ -42,7 +41,7 @@ class MultiDBProvider extends ServiceProvider if (isset($event->job->payload()['db'])) { - //\Log::error("Provider Setting DB = ".$event->job->payload()['db']); + \Log::error("Provider Setting DB = ".$event->job->payload()['db']); MultiDB::setDb($event->job->payload()['db']); } diff --git a/app/Repositories/BaseRepository.php b/app/Repositories/BaseRepository.php index c9247dcdd0b1..7ab6db4bc08f 100644 --- a/app/Repositories/BaseRepository.php +++ b/app/Repositories/BaseRepository.php @@ -251,6 +251,10 @@ class BaseRepository $state['finished_amount'] = $model->amount; $model = $model->service()->applyNumber()->save(); + + if ($model->company->update_products !== false) { + UpdateOrCreateProduct::dispatch($model->line_items, $model, $model->company); + } if ($class->name == Invoice::class) { @@ -258,10 +262,6 @@ class BaseRepository $model->ledger()->updateInvoiceBalance(($state['finished_amount'] - $state['starting_amount'])); } - if ($model->company->update_products !== false) { - UpdateOrCreateProduct::dispatch($model->line_items, $model, $model->company); - } - $model = $model->calc()->getInvoice(); } diff --git a/app/Services/Credit/CreditService.php b/app/Services/Credit/CreditService.php index 1ba9e09c056a..5cc3c3f8cb7a 100644 --- a/app/Services/Credit/CreditService.php +++ b/app/Services/Credit/CreditService.php @@ -2,6 +2,8 @@ namespace App\Services\Credit; use App\Models\Credit; +use App\Services\Credit\CreateInvitations; +use App\Services\Credit\MarkSent; class CreditService { @@ -36,6 +38,20 @@ class CreditService return $this; } + public function setStatus($status) + { + $this->credit->status_id = $status; + + return $this; + } + + public function markSent() + { + $this->credit = (new MarkSent($this->credit->client))->run($this->credit); + + return $this; + } + /** * Saves the credit * @return Credit object diff --git a/app/Services/Notification/NotificationService.php b/app/Services/Notification/NotificationService.php index 7d00acbe9677..fb3a3ced7d95 100644 --- a/app/Services/Notification/NotificationService.php +++ b/app/Services/Notification/NotificationService.php @@ -32,11 +32,32 @@ class NotificationService extends AbstractService } - public function run() + public function run($is_system = false) { $this->company->owner()->notify($this->notification); + if($is_system) + { + $this->notification->is_system = true; + + Notification::route('slack', $this->company->slack_webhook_url) + ->notify($this->notification); + } + + } + + /** + * Hosted notifications + * @return void + */ + public function ninja() + { + + Notification::route('slack', config('ninja.notification.slack')) + ->route('mail', config('ninja.notification.mail')) + ->notify($this->notification); + } } diff --git a/app/Services/Quote/QuoteService.php b/app/Services/Quote/QuoteService.php index ab0c4d5961a4..b98cb9a3e792 100644 --- a/app/Services/Quote/QuoteService.php +++ b/app/Services/Quote/QuoteService.php @@ -2,6 +2,7 @@ namespace App\Services\Quote; use App\Models\Quote; +use App\Services\Quote\CreateInvitations; class QuoteService { diff --git a/config/auth.php b/config/auth.php index af8c53f1bc3d..75a46ab80568 100644 --- a/config/auth.php +++ b/config/auth.php @@ -74,13 +74,11 @@ return [ 'providers' => [ 'users' => [ 'driver' => 'eloquent', - //'driver' => env('USER_AUTH_PROVIDER', 'eloquent'), 'model' => App\Models\User::class, ], 'contacts' => [ 'driver' => 'eloquent', -// 'driver' => env('CONTACT_AUTH_PROVIDER', 'eloquent'), 'model' => App\Models\ClientContact::class, ], diff --git a/config/ninja.php b/config/ninja.php index 2fe854a8aa76..704380bd0480 100644 --- a/config/ninja.php +++ b/config/ninja.php @@ -89,6 +89,7 @@ return [ ], 'notification' => [ 'slack' => env('SLACK_WEBHOOK_URL',''), + 'mail' => env('HOSTED_EMAIL',''), ], 'payment_terms' => [ [ diff --git a/resources/lang/en/texts.php b/resources/lang/en/texts.php index 030852e5fda5..7ef674ad7d65 100644 --- a/resources/lang/en/texts.php +++ b/resources/lang/en/texts.php @@ -3120,8 +3120,10 @@ $LANG = array( 'new_signup_text' => 'A new account has been created by :user - :email - from IP address: :ip', 'notification_payment_paid_subject' => 'Payment was made by :client', - 'notification_paid_paid' => 'A payment of :amount was made by client :client towards :invoice.', - + 'notification_partial_payment_paid_subject' => 'Partial payment was made by :client', + 'notification_payment_paid' => 'A payment of :amount was made by client :client towards :invoice', + 'notification_partial_payment_paid' => 'A partial payment of :amount was made by client :client towards :invoice', + 'notification_bot' => 'Notification Bot', 'email_link_not_working' => 'If button above isn\'t working for you, please click on the link', );