diff --git a/app/Export/CSV/BaseExport.php b/app/Export/CSV/BaseExport.php index cc4fe21f5efd..e36cab4e346a 100644 --- a/app/Export/CSV/BaseExport.php +++ b/app/Export/CSV/BaseExport.php @@ -11,27 +11,29 @@ namespace App\Export\CSV; +use App\Models\Task; +use App\Models\User; +use App\Models\Quote; use App\Models\Client; -use App\Models\ClientContact; -use App\Models\Company; use App\Models\Credit; -use App\Models\Document; +use App\Models\Vendor; +use App\Utils\Helpers; +use App\Models\Company; use App\Models\Expense; use App\Models\Invoice; use App\Models\Payment; use App\Models\Product; -use App\Models\PurchaseOrder; -use App\Models\Quote; -use App\Models\RecurringInvoice; -use App\Models\Task; -use App\Models\Vendor; -use App\Transformers\PaymentTransformer; -use App\Transformers\TaskTransformer; -use App\Utils\Helpers; -use App\Utils\Traits\MakesHash; -use Illuminate\Database\Eloquent\Builder; -use Illuminate\Support\Carbon; +use App\Models\Document; use League\Fractal\Manager; +use App\Models\ClientContact; +use App\Models\PurchaseOrder; +use Illuminate\Support\Carbon; +use App\Utils\Traits\MakesHash; +use App\Models\RecurringInvoice; +use App\Jobs\Document\ZipDocuments; +use App\Transformers\TaskTransformer; +use App\Transformers\PaymentTransformer; +use Illuminate\Database\Eloquent\Builder; use League\Fractal\Serializer\ArraySerializer; class BaseExport @@ -1258,4 +1260,32 @@ class BaseExport return $clean_row; } + public function queueDocuments(Builder $query) + { + + if($query->getModel() instanceof Document) + $documents = $query->pluck('id')->toArray(); + else{ + $documents = $query->cursor() + ->map(function ($entity){ + return $entity->documents()->pluck('id')->toArray(); + })->flatten() + ->toArray(); + } + + nlog($documents); + if(count($documents) > 0) { + + $user = $this->company->owner(); + + if(auth()->user() && auth()->user()->account_id == $this->company->account_id) + $user = auth()->user(); + + if($this->input['user_id']) + $user = User::where('id', $this->input['user_id'])->where('account_id', $this->company->account_id)->first(); + + ZipDocuments::dispatch($documents, $this->company, $user); + } + } + } diff --git a/app/Export/CSV/ClientExport.php b/app/Export/CSV/ClientExport.php index 5957a2d574c5..3fb7ee1eb08d 100644 --- a/app/Export/CSV/ClientExport.php +++ b/app/Export/CSV/ClientExport.php @@ -131,6 +131,10 @@ class ClientExport extends BaseExport $query = $this->addDateRange($query); + if($this->input['document_email_attachment'] ?? false) { + $this->queueDocuments($query); + } + return $query; } diff --git a/app/Export/CSV/CreditExport.php b/app/Export/CSV/CreditExport.php index b4c907747b38..1ef2af5fe70c 100644 --- a/app/Export/CSV/CreditExport.php +++ b/app/Export/CSV/CreditExport.php @@ -106,6 +106,10 @@ class CreditExport extends BaseExport ->where('is_deleted', 0); $query = $this->addDateRange($query); + + if($this->input['document_email_attachment'] ?? false) { + $this->queueDocuments($query); + } return $query; } diff --git a/app/Export/CSV/DocumentExport.php b/app/Export/CSV/DocumentExport.php index ba09d9389fee..cbe77f0f26ba 100644 --- a/app/Export/CSV/DocumentExport.php +++ b/app/Export/CSV/DocumentExport.php @@ -77,6 +77,10 @@ class DocumentExport extends BaseExport $query = Document::query()->where('company_id', $this->company->id); $query = $this->addDateRange($query); + + if($this->input['document_email_attachment'] ?? false) { + $this->queueDocuments($query); + } return $query; diff --git a/app/Export/CSV/ExpenseExport.php b/app/Export/CSV/ExpenseExport.php index 1ac3c96b777d..3ab505511330 100644 --- a/app/Export/CSV/ExpenseExport.php +++ b/app/Export/CSV/ExpenseExport.php @@ -103,6 +103,10 @@ class ExpenseExport extends BaseExport if(isset($this->input['categories'])) { $query = $this->addCategoryFilter($query, $this->input['categories']); } + + if($this->input['document_email_attachment'] ?? false) { + $this->queueDocuments($query); + } return $query; diff --git a/app/Export/CSV/InvoiceExport.php b/app/Export/CSV/InvoiceExport.php index 5ccb2daaaad1..546b3689ba90 100644 --- a/app/Export/CSV/InvoiceExport.php +++ b/app/Export/CSV/InvoiceExport.php @@ -62,10 +62,14 @@ class InvoiceExport extends BaseExport $query = $this->addDateRange($query); - if(isset($this->input['status'])) { + if($this->input['status'] ?? false) { $query = $this->addInvoiceStatusFilter($query, $this->input['status']); } + if($this->input['document_email_attachment'] ?? false) { + $this->queueDocuments($query); + } + return $query; } @@ -120,15 +124,11 @@ class InvoiceExport extends BaseExport if (is_array($parts) && $parts[0] == 'invoice' && array_key_exists($parts[1], $transformed_invoice)) { $entity[$key] = $transformed_invoice[$parts[1]]; } else { - // nlog($key); $entity[$key] = $this->decorator->transform($key, $invoice); - // $entity[$key] = ''; - // $entity[$key] = $this->resolveKey($key, $invoice, $this->invoice_transformer); } } - // return $entity; return $this->decorateAdvancedFields($invoice, $entity); } @@ -167,7 +167,6 @@ class InvoiceExport extends BaseExport $entity['invoice.user_id'] = $invoice->user ? $invoice->user->present()->name() : ''; } -nlog($entity); return $entity; } } diff --git a/app/Export/CSV/InvoiceItemExport.php b/app/Export/CSV/InvoiceItemExport.php index 76d4b7413f51..e56eb7142e4c 100644 --- a/app/Export/CSV/InvoiceItemExport.php +++ b/app/Export/CSV/InvoiceItemExport.php @@ -76,6 +76,10 @@ class InvoiceItemExport extends BaseExport $query = $this->addDateRange($query); $query = $this->applyFilters($query); + + if($this->input['document_email_attachment'] ?? false) { + $this->queueDocuments($query); + } return $query; @@ -91,7 +95,6 @@ class InvoiceItemExport extends BaseExport return ['identifier' => $key, 'display_value' => $headerdisplay[$value]]; })->toArray(); - $query->cursor() ->each(function ($resource) { $this->iterateItems($resource); diff --git a/app/Export/CSV/PaymentExport.php b/app/Export/CSV/PaymentExport.php index f9f9c21c4ea3..d4646d143078 100644 --- a/app/Export/CSV/PaymentExport.php +++ b/app/Export/CSV/PaymentExport.php @@ -60,6 +60,10 @@ class PaymentExport extends BaseExport ->where('is_deleted', 0); $query = $this->addDateRange($query); + + if($this->input['document_email_attachment'] ?? false) { + $this->queueDocuments($query); + } return $query; } diff --git a/app/Export/CSV/ProductExport.php b/app/Export/CSV/ProductExport.php index d223c1b1f143..5c2dd3401ebc 100644 --- a/app/Export/CSV/ProductExport.php +++ b/app/Export/CSV/ProductExport.php @@ -77,6 +77,10 @@ class ProductExport extends BaseExport ->where('is_deleted', 0); $query = $this->addDateRange($query); + + if($this->input['document_email_attachment'] ?? false) { + $this->queueDocuments($query); + } return $query; diff --git a/app/Export/CSV/PurchaseOrderExport.php b/app/Export/CSV/PurchaseOrderExport.php index ab94b685fb51..094fbc87fcbf 100644 --- a/app/Export/CSV/PurchaseOrderExport.php +++ b/app/Export/CSV/PurchaseOrderExport.php @@ -107,6 +107,10 @@ class PurchaseOrderExport extends BaseExport ->where('is_deleted', 0); $query = $this->addDateRange($query); + + if($this->input['document_email_attachment'] ?? false) { + $this->queueDocuments($query); + } return $query; diff --git a/app/Export/CSV/PurchaseOrderItemExport.php b/app/Export/CSV/PurchaseOrderItemExport.php index a76a8337b826..ccdd7a8dc27d 100644 --- a/app/Export/CSV/PurchaseOrderItemExport.php +++ b/app/Export/CSV/PurchaseOrderItemExport.php @@ -67,6 +67,10 @@ class PurchaseOrderItemExport extends BaseExport $query = $this->addDateRange($query); + if($this->input['document_email_attachment'] ?? false) { + $this->queueDocuments($query); + } + return $query; } diff --git a/app/Export/CSV/QuoteExport.php b/app/Export/CSV/QuoteExport.php index e324fdc0b90b..1242ba19f6de 100644 --- a/app/Export/CSV/QuoteExport.php +++ b/app/Export/CSV/QuoteExport.php @@ -69,6 +69,10 @@ class QuoteExport extends BaseExport $query = $this->addDateRange($query); + if($this->input['document_email_attachment'] ?? false) { + $this->queueDocuments($query); + } + return $query; } diff --git a/app/Export/CSV/QuoteItemExport.php b/app/Export/CSV/QuoteItemExport.php index 01e9b2a02a03..b7b86c9a123f 100644 --- a/app/Export/CSV/QuoteItemExport.php +++ b/app/Export/CSV/QuoteItemExport.php @@ -69,6 +69,10 @@ class QuoteItemExport extends BaseExport ->where('is_deleted', 0); $query = $this->addDateRange($query); + + if($this->input['document_email_attachment'] ?? false) { + $this->queueDocuments($query); + } return $query; diff --git a/app/Export/CSV/TaskExport.php b/app/Export/CSV/TaskExport.php index fb128b022e8d..7e91a32dadad 100644 --- a/app/Export/CSV/TaskExport.php +++ b/app/Export/CSV/TaskExport.php @@ -72,6 +72,10 @@ class TaskExport extends BaseExport $query = $this->addDateRange($query); + if($this->input['document_email_attachment'] ?? false) { + $this->queueDocuments($query); + } + return $query; } diff --git a/app/Export/CSV/VendorExport.php b/app/Export/CSV/VendorExport.php index f82314d0124a..a98ee80f825a 100644 --- a/app/Export/CSV/VendorExport.php +++ b/app/Export/CSV/VendorExport.php @@ -66,6 +66,10 @@ class VendorExport extends BaseExport $query = $this->addDateRange($query); + if($this->input['document_email_attachment'] ?? false) { + $this->queueDocuments($query); + } + return $query; } diff --git a/app/Http/Requests/Report/GenericReportRequest.php b/app/Http/Requests/Report/GenericReportRequest.php index 42d6fa545450..6a0bdfad51f4 100644 --- a/app/Http/Requests/Report/GenericReportRequest.php +++ b/app/Http/Requests/Report/GenericReportRequest.php @@ -37,6 +37,7 @@ class GenericReportRequest extends Request 'start_date' => 'bail|required_if:date_range,custom|nullable|date', 'report_keys' => 'present|array', 'send_email' => 'required|bool', + 'document_email_attachment' => 'sometimes|bool' // 'status' => 'sometimes|string|nullable|in:all,draft,sent,viewed,paid,unpaid,overdue', ]; } @@ -62,6 +63,8 @@ class GenericReportRequest extends Request $input['end_date'] = null; } + $input['user_id'] = auth()->user()->id; + $this->replace($input); } } diff --git a/app/Jobs/Document/ZipDocuments.php b/app/Jobs/Document/ZipDocuments.php index 9683ee1ad8b8..365654e6d111 100644 --- a/app/Jobs/Document/ZipDocuments.php +++ b/app/Jobs/Document/ZipDocuments.php @@ -49,9 +49,9 @@ class ZipDocuments implements ShouldQueue public $tries = 1; /** - * @param $invoices + * @param array $document_ids * @param Company $company - * @param $email + * @param User $user * @deprecated confirm to be deleted * Create a new job instance. */ diff --git a/app/Jobs/Payment/EmailPayment.php b/app/Jobs/Payment/EmailPayment.php index e79cf8c73cb4..0c15d43d17cd 100644 --- a/app/Jobs/Payment/EmailPayment.php +++ b/app/Jobs/Payment/EmailPayment.php @@ -68,7 +68,7 @@ class EmailPayment implements ShouldQueue $this->payment->load('invoices'); if (!$this->contact) { - $this->contact = $this->payment->client->contacts()->first(); + $this->contact = $this->payment->client->contacts()->orderBy('is_primary', 'desc')->first(); } $this->contact->load('client'); diff --git a/app/Jobs/Report/PreviewReport.php b/app/Jobs/Report/PreviewReport.php index 867211b0e87e..0fa253667a09 100644 --- a/app/Jobs/Report/PreviewReport.php +++ b/app/Jobs/Report/PreviewReport.php @@ -48,8 +48,6 @@ class PreviewReport implements ShouldQueue $report = $export->run(); } - // nlog($report); - Cache::put($this->hash, $report, 60 * 60); } diff --git a/app/Models/ClientContact.php b/app/Models/ClientContact.php index 2f5a948feae8..c2a7e340fc84 100644 --- a/app/Models/ClientContact.php +++ b/app/Models/ClientContact.php @@ -254,7 +254,7 @@ class ClientContact extends Authenticatable implements HasLocalePreference { return $this->hasMany(CreditInvitation::class); } - + public function sendPasswordResetNotification($token) { $this->token = $token; diff --git a/app/Services/Payment/SendEmail.php b/app/Services/Payment/SendEmail.php index eda37583ef0e..bb0872706dfc 100644 --- a/app/Services/Payment/SendEmail.php +++ b/app/Services/Payment/SendEmail.php @@ -14,22 +14,38 @@ namespace App\Services\Payment; use App\Jobs\Payment\EmailPayment; use App\Models\ClientContact; use App\Models\Payment; +use Illuminate\Database\QueryException; class SendEmail { - public function __construct(public Payment $payment, public ?ClientContact $contact) - { - } + public function __construct(public Payment $payment, public ?ClientContact $contact) {} /** * Builds the correct template to send. */ public function run() { - $this->payment->load('company', 'client.contacts', 'invoices'); + $this->payment->load('company', 'invoices'); if (!$this->contact) { - $this->contact = $this->payment->client->contacts()->first(); + + if($invoice = $this->payment->invoices->first() ?? false) { + + $invitation = + $invoice + ->invitations() + ->whereHas("contact", function ($q) { + $q->where('send_email', true)->orderBy("is_primary", 'ASC'); + }) + ->first(); + + if($invitation) { + $this->contact = $invitation->contact; + } else { + $this->contact = $this->payment->client->contacts()->orderBy('send_email', 'desc')->orderBy('is_primary', 'desc')->first(); + } + } + } EmailPayment::dispatch($this->payment, $this->payment->company, $this->contact); diff --git a/database/migrations/2024_01_09_084515_product_cost_field_population.php b/database/migrations/2024_01_09_084515_product_cost_field_population.php index c38dd91d256a..de7168b9a121 100644 --- a/database/migrations/2024_01_09_084515_product_cost_field_population.php +++ b/database/migrations/2024_01_09_084515_product_cost_field_population.php @@ -23,9 +23,10 @@ return new class extends Migration Invoice::withTrashed() ->where('is_deleted', false) ->cursor() - ->each(function (Invoice $invoice) { - + ->each(function (Invoice $invoice) { + $hit = false; + $line_items = $invoice->line_items; if(is_array($line_items)) @@ -35,14 +36,18 @@ return new class extends Migration if($product = Product::where('company_id', $invoice->company_id)->where('product_key', $item->product_key)->where('cost', '>', 0)->first()) { - if((property_exists($item, 'product_cost') && $item->product_cost == 0) || !property_exists($item, 'product_cost')) + if((property_exists($item, 'product_cost') && $item->product_cost == 0) || !property_exists($item, 'product_cost')){ + $hit = true; $line_items[$key]->product_cost = (float)$product->cost; + } } } - - $invoice->line_items = $line_items; - $invoice->saveQuietly(); + + if($hit){ + $invoice->line_items = $line_items; + $invoice->saveQuietly(); + } } }); } diff --git a/tests/Unit/EntityTest.php b/tests/Unit/EntityTest.php index 99076e906109..330e3bc8fc02 100644 --- a/tests/Unit/EntityTest.php +++ b/tests/Unit/EntityTest.php @@ -11,10 +11,22 @@ namespace Tests\Unit; -use App\Helpers\Invoice\InvoiceSum; -use Illuminate\Foundation\Testing\DatabaseTransactions; -use Tests\MockAccountData; use Tests\TestCase; +use App\Models\Invoice; +use Tests\MockAccountData; +use App\Helpers\Invoice\InvoiceSum; +use App\Models\Client; +use App\Models\Credit; +use App\Models\Document; +use App\Models\Expense; +use App\Models\Payment; +use App\Models\Product; +use App\Models\Project; +use App\Models\PurchaseOrder; +use App\Models\Quote; +use App\Models\Task; +use App\Models\Vendor; +use Illuminate\Foundation\Testing\DatabaseTransactions; /** * @test @@ -55,4 +67,21 @@ class EntityTest extends TestCase $this->assertEquals('InvoiceInvitation', class_basename($invitation)); } -} + + public function testDocumentRelationExists() + { + + $this->assertTrue(method_exists(Invoice::class, 'documents')); + $this->assertTrue(method_exists(Quote::class, 'documents')); + $this->assertTrue(method_exists(Credit::class, 'documents')); + $this->assertTrue(method_exists(PurchaseOrder::class, 'documents')); + $this->assertTrue(method_exists(Client::class, 'documents')); + $this->assertTrue(method_exists(Vendor::class, 'documents')); + $this->assertTrue(method_exists(Product::class, 'documents')); + $this->assertTrue(method_exists(Payment::class, 'documents')); + $this->assertTrue(method_exists(Expense::class, 'documents')); + $this->assertTrue(method_exists(Project::class, 'documents')); + $this->assertTrue(method_exists(Task::class, 'documents')); + + } +} \ No newline at end of file