diff --git a/app/DataMapper/EmailTemplateDefaults.php b/app/DataMapper/EmailTemplateDefaults.php index 03e212557147..5cdc7b915c23 100644 --- a/app/DataMapper/EmailTemplateDefaults.php +++ b/app/DataMapper/EmailTemplateDefaults.php @@ -62,7 +62,7 @@ class EmailTemplateDefaults case 'email_template_custom3': return self::emailInvoiceTemplate(); case 'email_template_purchase_order': - return self::emailPurchaseOrderSubject(); + return self::emailPurchaseOrderTemplate(); break; /* Subject */ @@ -157,7 +157,7 @@ class EmailTemplateDefaults public static function emailPurchaseOrderSubject() { - return ctrans('texts.purchase_order_subject', ['number' => '$number']); + return ctrans('texts.purchase_order_subject', ['number' => '$number', 'account' => '$account']); } public static function emailPurchaseOrderTemplate() diff --git a/app/Events/PurchaseOrder/PurchaseOrderWasEmailed.php b/app/Events/PurchaseOrder/PurchaseOrderWasEmailed.php index 7836a8442636..7674039d7027 100644 --- a/app/Events/PurchaseOrder/PurchaseOrderWasEmailed.php +++ b/app/Events/PurchaseOrder/PurchaseOrderWasEmailed.php @@ -13,6 +13,7 @@ namespace App\Events\PurchaseOrder; use App\Models\Company; use App\Models\PurchaseOrder; +use App\Models\PurchaseOrderInvitation; use Illuminate\Queue\SerializesModels; /** @@ -25,7 +26,7 @@ class PurchaseOrderWasEmailed /** * @var PurchaseOrder */ - public $purchase_order; + public $invitation; public $company; @@ -38,9 +39,9 @@ class PurchaseOrderWasEmailed * @param Company $company * @param array $event_vars */ - public function __construct(PurchaseOrder $purchase_order, Company $company, array $event_vars) + public function __construct(PurchaseOrderInvitation $invitation, Company $company, array $event_vars) { - $this->purchase_order = $purchase_order; + $this->invitation = $invitation; $this->company = $company; $this->event_vars = $event_vars; } diff --git a/app/Http/Controllers/PurchaseOrderController.php b/app/Http/Controllers/PurchaseOrderController.php index 61877a56d6d7..ad25c6fabe46 100644 --- a/app/Http/Controllers/PurchaseOrderController.php +++ b/app/Http/Controllers/PurchaseOrderController.php @@ -23,6 +23,7 @@ use App\Http\Requests\PurchaseOrder\EditPurchaseOrderRequest; use App\Http\Requests\PurchaseOrder\ShowPurchaseOrderRequest; use App\Http\Requests\PurchaseOrder\StorePurchaseOrderRequest; use App\Http\Requests\PurchaseOrder\UpdatePurchaseOrderRequest; +use App\Jobs\Invoice\PurchaseOrderEmail; use App\Jobs\Invoice\ZipInvoices; use App\Models\Client; use App\Models\PurchaseOrder; @@ -183,6 +184,7 @@ class PurchaseOrderController extends BaseController $purchase_order = $purchase_order->service() ->fillDefaults() + ->triggeredActions($request) ->save(); event(new PurchaseOrderWasCreated($purchase_order, $purchase_order->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null))); @@ -627,7 +629,7 @@ class PurchaseOrderController extends BaseController case 'email': //check query parameter for email_type and set the template else use calculateTemplate - + PurchaseOrderEmail::dispatch($purchase_order, $purchase_order->company); default: return response()->json(['message' => ctrans('texts.action_unavailable', ['action' => $action])], 400); diff --git a/app/Jobs/PurchaseOrder/PurchaseOrderEmail.php b/app/Jobs/PurchaseOrder/PurchaseOrderEmail.php new file mode 100644 index 000000000000..d27ffdd21ae7 --- /dev/null +++ b/app/Jobs/PurchaseOrder/PurchaseOrderEmail.php @@ -0,0 +1,102 @@ +purchase_order = $purchase_order; + $this->company = $company; + $this->template_data = $template_data; + } + + /** + * Execute the job. + * + * + * @return void + */ + public function handle() + { + MultiDB::setDb($this->company->db); + + $this->purchase_order->last_sent_date = now(); + + $this->purchase_order->invitations->load('contact.vendor.country', 'purchase_order.vendor.country', 'purchase_order.company')->each(function ($invitation) { + + /* Don't fire emails if the company is disabled */ + if ($this->company->is_disabled) + return true; + + /* Set DB */ + MultiDB::setDB($this->company->db); + + App::forgetInstance('translator'); + $t = app('translator'); + App::setLocale($invitation->contact->preferredLocale()); + $t->replace(Ninja::transformTranslations($this->company->settings)); + + /* Mark entity sent */ + $invitation->purchase_order->service()->markSent()->save(); + + $email_builder = (new PurchaseOrderEmailEngine($invitation, 'purchase_order', $this->template_data))->build(); + + $nmo = new NinjaMailerObject; + $nmo->mailable = new VendorTemplateEmail($email_builder, $invitation->contact, $invitation); + $nmo->company = $this->company; + $nmo->settings = $this->company->settings; + $nmo->to_user = $invitation->contact; + $nmo->entity_string = 'purchase_order'; + $nmo->invitation = $invitation; + $nmo->reminder_template = 'purchase_order'; + $nmo->entity = $invitation->purchase_order; + + NinjaMailerJob::dispatchNow($nmo); + + + }); + + if ($this->purchase_order->invitations->count() >= 1) { + event(new PurchaseOrderWasEmailed($this->purchase_order->invitations->first(), $this->purchase_order->invitations->first()->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null))); + } + + } + +} diff --git a/app/Mail/Engine/PurchaseOrderEmailEngine.php b/app/Mail/Engine/PurchaseOrderEmailEngine.php new file mode 100644 index 000000000000..d3b2fcbad5bd --- /dev/null +++ b/app/Mail/Engine/PurchaseOrderEmailEngine.php @@ -0,0 +1,207 @@ +invitation = $invitation; + $this->reminder_template = $reminder_template; //'purchase_order' + $this->vendor = $invitation->contact->vendor; + $this->purchase_order = $invitation->purchase_order; + $this->contact = $invitation->contact; + $this->template_data = $template_data; + } + + public function build() + { + + App::forgetInstance('translator'); + $t = app('translator'); + $t->replace(Ninja::transformTranslations($this->vendor->company->settings)); + + if (is_array($this->template_data) && array_key_exists('body', $this->template_data) && strlen($this->template_data['body']) > 0) { + $body_template = $this->template_data['body']; + } elseif (strlen($this->vendor->getSetting('email_template_'.$this->reminder_template)) > 0) { + $body_template = $this->vendor->getSetting('email_template_'.$this->reminder_template); + } else { + $body_template = EmailTemplateDefaults::getDefaultTemplate('email_template_'.$this->reminder_template, $this->vendor->company->locale()); + } + + /* Use default translations if a custom message has not been set*/ + if (iconv_strlen($body_template) == 0) { + $body_template = trans( + 'texts.invoice_message', + [ + 'invoice' => $this->purchase_order->number, + 'company' => $this->purchase_order->company->present()->name(), + 'amount' => Number::formatMoney($this->purchase_order->balance, $this->vendor), + ], + null, + $this->vendor->company->locale() + ); + + $body_template .= '
$view_button
'; + + } + $text_body = trans( + 'texts.purchase_order_message', + [ + 'purchase_order' => $this->purchase_order->number, + 'company' => $this->purchase_order->company->present()->name(), + 'amount' => Number::formatMoney($this->purchase_order->balance, $this->vendor), + ], + null, + $this->vendor->company->locale() + ) . "\n\n" . $this->invitation->getLink(); + + if (is_array($this->template_data) && array_key_exists('subject', $this->template_data) && strlen($this->template_data['subject']) > 0) { + $subject_template = $this->template_data['subject']; + } elseif (strlen($this->vendor->getSetting('email_subject_'.$this->reminder_template)) > 0) { + $subject_template = $this->vendor->getSetting('email_subject_'.$this->reminder_template); + } else { + $subject_template = EmailTemplateDefaults::getDefaultTemplate('email_subject_'.$this->reminder_template, $this->vendor->company->locale()); + + } + + if (iconv_strlen($subject_template) == 0) { + $subject_template = trans( + 'texts.purchase_order_subject', + [ + 'number' => $this->purchase_order->number, + 'account' => $this->purchase_order->company->present()->name(), + ], + null, + $this->vendor->company->locale() + ); + } + + $this->setTemplate($this->vendor->getSetting('email_style')) + ->setContact($this->contact) + ->setVariables((new VendorHtmlEngine($this->invitation))->makeValues())//move make values into the htmlengine + ->setSubject($subject_template) + ->setBody($body_template) + ->setFooter("".ctrans('texts.view_purchase_order').'') + ->setViewLink($this->invitation->getLink()) + ->setViewText(ctrans('texts.view_purchase_order')) + ->setInvitation($this->invitation) + ->setTextBody($text_body); + + if ($this->vendor->getSetting('pdf_email_attachment') !== false && $this->purchase_order->company->account->hasFeature(Account::FEATURE_PDF_ATTACHMENT)) { + + if(Ninja::isHosted()) + $this->setAttachments([$this->purchase_order->pdf_file_path($this->invitation, 'url', true)]); + else + $this->setAttachments([$this->purchase_order->pdf_file_path($this->invitation)]); + + } + + //attach third party documents + if($this->vendor->getSetting('document_email_attachment') !== false && $this->purchase_order->company->account->hasFeature(Account::FEATURE_DOCUMENTS)){ + + // Storage::url + foreach($this->purchase_order->documents as $document){ + $this->setAttachments([['path' => $document->filePath(), 'name' => $document->name, 'mime' => $document->type]]); + } + + foreach($this->purchase_order->company->documents as $document){ + $this->setAttachments([['path' => $document->filePath(), 'name' => $document->name, 'mime' => $document->type]]); + } + + // $line_items = $this->purchase_order->line_items; + + + // foreach($line_items as $item) + // { + + // $expense_ids = []; + + // if(property_exists($item, 'expense_id')) + // { + // $expense_ids[] = $item->expense_id; + // } + + // if(count($expense_ids) > 0){ + + // $expenses = Expense::whereIn('id', $this->transformKeys($expense_ids)) + // ->where('invoice_documents', 1) + // ->cursor() + // ->each(function ($expense){ + + // foreach($expense->documents as $document) + // { + // $this->setAttachments([['path' => $document->filePath(), 'name' => $document->name, 'mime' => $document->type]]); + // } + + // }); + // } + + // $task_ids = []; + + // if(property_exists($item, 'task_id')) + // { + // $task_ids[] = $item->task_id; + // } + + // if(count($task_ids) > 0 && $this->purchase_order->company->purchase_order_task_documents){ + + // $tasks = Task::whereIn('id', $this->transformKeys($task_ids)) + // ->cursor() + // ->each(function ($task){ + + // foreach($task->documents as $document) + // { + // $this->setAttachments([['path' => $document->filePath(), 'name' => $document->name, 'mime' => $document->type]]); + // } + + // }); + // } + + // } + + + } + + return $this; + } +} \ No newline at end of file diff --git a/app/Mail/VendorTemplateEmail.php b/app/Mail/VendorTemplateEmail.php new file mode 100644 index 000000000000..2612f90c6209 --- /dev/null +++ b/app/Mail/VendorTemplateEmail.php @@ -0,0 +1,132 @@ +build_email = $build_email; + + $this->contact = $contact; + + $this->vendor = $contact->vendor; + + $this->company = $contact->company; + + $this->invitation = $invitation; + } + + public function build() + { + + $template_name = 'email.template.'.$this->build_email->getTemplate(); + + if ($this->build_email->getTemplate() == 'light' || $this->build_email->getTemplate() == 'dark') { + $template_name = 'email.template.client'; + } + + if($this->build_email->getTemplate() == 'custom') { + $this->build_email->setBody(str_replace('$body', $this->build_email->getBody(), $this->client->getSetting('email_style_custom'))); + } + + $settings = $this->company->settings; + + if ($this->build_email->getTemplate() !== 'custom') { + $this->build_email->setBody( + DesignHelpers::parseMarkdownToHtml($this->build_email->getBody()) + ); + } + + if($this->invitation) + { + $html_variables = (new VendorHtmlEngine($this->invitation))->makeValues(); + $signature = str_replace(array_keys($html_variables), array_values($html_variables), $settings->email_signature); + } + else + $signature = $settings->email_signature; + + if(property_exists($settings, 'email_from_name') && strlen($settings->email_from_name) > 1) + $email_from_name = $settings->email_from_name; + else + $email_from_name = $this->company->present()->name(); + + $this->from(config('mail.from.address'), $email_from_name); + + if (strlen($settings->bcc_email) > 1) + $this->bcc(explode(",",str_replace(" ", "", $settings->bcc_email)));//remove whitespace if any has been inserted. + + $this->subject($this->build_email->getSubject()) + ->text('email.template.text', [ + 'text_body' => $this->build_email->getTextBody(), + 'whitelabel' => $this->vendor->user->account->isPaid() ? true : false, + 'settings' => $settings, + ]) + ->view($template_name, [ + 'greeting' => ctrans('texts.email_salutation', ['name' => $this->contact->present()->name()]), + 'body' => $this->build_email->getBody(), + 'footer' => $this->build_email->getFooter(), + 'view_link' => $this->build_email->getViewLink(), + 'view_text' => $this->build_email->getViewText(), + 'title' => '', + 'signature' => $signature, + 'settings' => $settings, + 'company' => $this->company, + 'whitelabel' => $this->vendor->user->account->isPaid() ? true : false, + 'logo' => $this->company->present()->logo($settings), + ]) + ->withSwiftMessage(function ($message) { + $message->getHeaders()->addTextHeader('Tag', $this->company->company_key); + $message->invitation = $this->invitation; + }); + + /*In the hosted platform we need to slow things down a little for Storage to catch up.*/ + if(Ninja::isHosted()) + sleep(1); + + foreach ($this->build_email->getAttachments() as $file) { + + if(is_string($file)) + $this->attach($file); + elseif(is_array($file)) + $this->attach($file['path'], ['as' => $file['name'], 'mime' => $file['mime']]); + + } + + return $this; + } +} diff --git a/app/Models/Account.php b/app/Models/Account.php index 8af56a3a590d..4f9f9a333e0d 100644 --- a/app/Models/Account.php +++ b/app/Models/Account.php @@ -57,6 +57,7 @@ class Account extends BaseModel 'utm_content', 'user_agent', 'platform', + // 'set_react_as_default_ap', ]; /** diff --git a/app/Models/VendorContact.php b/app/Models/VendorContact.php index 2f5f9447cc04..d4a4bd92f91a 100644 --- a/app/Models/VendorContact.php +++ b/app/Models/VendorContact.php @@ -110,7 +110,7 @@ class VendorContact extends Authenticatable implements HasLocalePreference public function sendPasswordResetNotification($token) { - $this->notify(new ClientContactResetPassword($token)); + // $this->notify(new ClientContactResetPassword($token)); } public function preferredLocale() @@ -118,12 +118,9 @@ class VendorContact extends Authenticatable implements HasLocalePreference $languages = Cache::get('languages'); return $languages->filter(function ($item) { - return $item->id == $this->client->getSetting('language_id'); + return $item->id == $this->company->getSetting('language_id'); })->first()->locale; - //$lang = Language::find($this->client->getSetting('language_id')); - - //return $lang->locale; } /** diff --git a/app/Services/PdfMaker/Design.php b/app/Services/PdfMaker/Design.php index dcbc8f39bff4..01be541aa1c0 100644 --- a/app/Services/PdfMaker/Design.php +++ b/app/Services/PdfMaker/Design.php @@ -56,6 +56,10 @@ class Design extends BaseDesign /** @var Payment[] */ public $payments; + public $settings_object; + + public $company; + /** @var array */ public $aging = []; @@ -80,6 +84,7 @@ class Design extends BaseDesign Str::endsWith('.html', $design) ? $this->design = $design : $this->design = "{$design}.html"; $this->options = $options; + } public function html(): ?string @@ -574,19 +579,19 @@ class Design extends BaseDesign foreach ($this->context['pdf_variables']["{$type}_columns"] as $column) { if (array_key_exists($column, $aliases)) { - $elements[] = ['element' => 'th', 'content' => $aliases[$column] . '_label', 'properties' => ['data-ref' => "{$type}_table-" . substr($aliases[$column], 1) . '-th', 'hidden' => $this->client->getSetting('hide_empty_columns_on_pdf')]]; - } elseif ($column == '$product.discount' && !$this->client->company->enable_product_discount) { + $elements[] = ['element' => 'th', 'content' => $aliases[$column] . '_label', 'properties' => ['data-ref' => "{$type}_table-" . substr($aliases[$column], 1) . '-th', 'hidden' => $this->settings_object->getSetting('hide_empty_columns_on_pdf')]]; + } elseif ($column == '$product.discount' && !$this->company->enable_product_discount) { $elements[] = ['element' => 'th', 'content' => $column . '_label', 'properties' => ['data-ref' => "{$type}_table-" . substr($column, 1) . '-th', 'style' => 'display: none;']]; - } elseif ($column == '$product.quantity' && !$this->client->company->enable_product_quantity) { + } elseif ($column == '$product.quantity' && !$this->company->enable_product_quantity) { $elements[] = ['element' => 'th', 'content' => $column . '_label', 'properties' => ['data-ref' => "{$type}_table-" . substr($column, 1) . '-th', 'style' => 'display: none;']]; } elseif ($column == '$product.tax_rate1') { - $elements[] = ['element' => 'th', 'content' => $column . '_label', 'properties' => ['data-ref' => "{$type}_table-product.tax1-th", 'hidden' => $this->client->getSetting('hide_empty_columns_on_pdf')]]; + $elements[] = ['element' => 'th', 'content' => $column . '_label', 'properties' => ['data-ref' => "{$type}_table-product.tax1-th", 'hidden' => $this->settings_object->getSetting('hide_empty_columns_on_pdf')]]; } elseif ($column == '$product.tax_rate2') { - $elements[] = ['element' => 'th', 'content' => $column . '_label', 'properties' => ['data-ref' => "{$type}_table-product.tax2-th", 'hidden' => $this->client->getSetting('hide_empty_columns_on_pdf')]]; + $elements[] = ['element' => 'th', 'content' => $column . '_label', 'properties' => ['data-ref' => "{$type}_table-product.tax2-th", 'hidden' => $this->settings_object->getSetting('hide_empty_columns_on_pdf')]]; } elseif ($column == '$product.tax_rate3') { - $elements[] = ['element' => 'th', 'content' => $column . '_label', 'properties' => ['data-ref' => "{$type}_table-product.tax3-th", 'hidden' => $this->client->getSetting('hide_empty_columns_on_pdf')]]; + $elements[] = ['element' => 'th', 'content' => $column . '_label', 'properties' => ['data-ref' => "{$type}_table-product.tax3-th", 'hidden' => $this->settings_object->getSetting('hide_empty_columns_on_pdf')]]; } else { - $elements[] = ['element' => 'th', 'content' => $column . '_label', 'properties' => ['data-ref' => "{$type}_table-" . substr($column, 1) . '-th', 'hidden' => $this->client->getSetting('hide_empty_columns_on_pdf')]]; + $elements[] = ['element' => 'th', 'content' => $column . '_label', 'properties' => ['data-ref' => "{$type}_table-" . substr($column, 1) . '-th', 'hidden' => $this->settings_object->getSetting('hide_empty_columns_on_pdf')]]; } } @@ -677,9 +682,9 @@ class Design extends BaseDesign if ($cell == '$task.rate') { $element['elements'][] = ['element' => 'td', 'content' => $row['$task.cost'], 'properties' => ['data-ref' => 'task_table-task.cost-td']]; - } elseif ($cell == '$product.discount' && !$this->client->company->enable_product_discount) { + } elseif ($cell == '$product.discount' && !$this->company->enable_product_discount) { $element['elements'][] = ['element' => 'td', 'content' => $row['$product.discount'], 'properties' => ['data-ref' => 'product_table-product.discount-td', 'style' => 'display: none;']]; - } elseif ($cell == '$product.quantity' && !$this->client->company->enable_product_quantity) { + } elseif ($cell == '$product.quantity' && !$this->company->enable_product_quantity) { $element['elements'][] = ['element' => 'td', 'content' => $row['$product.quantity'], 'properties' => ['data-ref' => 'product_table-product.quantity-td', 'style' => 'display: none;']]; } elseif ($cell == '$task.hours') { $element['elements'][] = ['element' => 'td', 'content' => $row['$task.quantity'], 'properties' => ['data-ref' => 'task_table-task.hours-td']]; @@ -807,7 +812,7 @@ class Design extends BaseDesign ]]; } elseif (Str::startsWith($variable, '$custom')) { $field = explode('_', $variable); - $visible = is_object($this->client->company->custom_fields) && property_exists($this->client->company->custom_fields, $field[1]) && !empty($this->client->company->custom_fields->{$field[1]}); + $visible = is_object($this->company->custom_fields) && property_exists($this->company->custom_fields, $field[1]) && !empty($this->company->custom_fields->{$field[1]}); $elements[1]['elements'][] = ['element' => 'div', 'elements' => [ ['element' => 'span', 'content' => $variable . '_label', 'properties' => ['hidden' => !$visible, 'data-ref' => 'totals_table-' . substr($variable, 1) . '-label']], diff --git a/app/Services/PdfMaker/Designs/Utilities/DesignHelpers.php b/app/Services/PdfMaker/Designs/Utilities/DesignHelpers.php index 944c518db166..ff449e8f1ae6 100644 --- a/app/Services/PdfMaker/Designs/Utilities/DesignHelpers.php +++ b/app/Services/PdfMaker/Designs/Utilities/DesignHelpers.php @@ -60,6 +60,10 @@ trait DesignHelpers $this->document(); + $this->settings_object = $this->vendor ? $this->vendor->company : $this->client; + + $this->company = $this->vendor ? $this->vendor->company : $this->client->company; + return $this; } diff --git a/app/Services/PurchaseOrder/CreateInvitations.php b/app/Services/PurchaseOrder/CreateInvitations.php index fa01a8457b27..cd8634fc5de1 100644 --- a/app/Services/PurchaseOrder/CreateInvitations.php +++ b/app/Services/PurchaseOrder/CreateInvitations.php @@ -42,7 +42,7 @@ class CreateInvitations extends AbstractService public function run() { - $contacts = $this->purchase_order->vendor->contacts()->where('send_email', true)->get(); + $contacts = $this->purchase_order->vendor->contacts()->get(); if($contacts->count() == 0){ $this->createBlankContact(); diff --git a/app/Services/PurchaseOrder/PurchaseOrderService.php b/app/Services/PurchaseOrder/PurchaseOrderService.php index 69e6066b992a..89d2b64a8b31 100644 --- a/app/Services/PurchaseOrder/PurchaseOrderService.php +++ b/app/Services/PurchaseOrder/PurchaseOrderService.php @@ -11,11 +11,12 @@ namespace App\Services\PurchaseOrder; - +use App\Jobs\Vendor\CreatePurchaseOrderPdf; use App\Models\PurchaseOrder; use App\Services\PurchaseOrder\ApplyNumber; use App\Services\PurchaseOrder\CreateInvitations; use App\Services\PurchaseOrder\GetPurchaseOrderPdf; +use App\Services\PurchaseOrder\TriggeredActions; use App\Utils\Traits\MakesHash; class PurchaseOrderService @@ -62,6 +63,13 @@ class PurchaseOrderService return $this; } + public function triggeredActions($request) + { + $this->purchase_order = (new TriggeredActions($this->purchase_order->load('invitations'), $request))->run(); + + return $this; + } + public function getPurchaseOrderPdf($contact = null) { return (new GetPurchaseOrderPdf($this->purchase_order, $contact))->run(); @@ -81,6 +89,34 @@ class PurchaseOrderService return $this; } + + public function touchPdf($force = false) + { + try { + + if($force){ + + $this->purchase_order->invitations->each(function ($invitation) { + CreatePurchaseOrderPdf::dispatchNow($invitation); + }); + + return $this; + } + + $this->purchase_order->invitations->each(function ($invitation) { + CreatePurchaseOrderPdf::dispatch($invitation); + }); + + } + catch(\Exception $e){ + + nlog("failed creating purchase orders in Touch PDF"); + + } + + return $this; + } + /** * Saves the purchase order. * @return \App\Models\PurchaseOrder object diff --git a/app/Services/PurchaseOrder/TriggeredActions.php b/app/Services/PurchaseOrder/TriggeredActions.php new file mode 100644 index 000000000000..76735129cf13 --- /dev/null +++ b/app/Services/PurchaseOrder/TriggeredActions.php @@ -0,0 +1,65 @@ +request = $request; + + $this->purchase_order = $purchase_order; + } + + public function run() + { + + if ($this->request->has('send_email') && $this->request->input('send_email') == 'true') { + $this->purchase_order->service()->markSent()->touchPdf()->save(); + $this->sendEmail(); + } + + if ($this->request->has('mark_sent') && $this->request->input('mark_sent') == 'true') { + $this->purchase_order = $this->purchase_order->service()->markSent()->touchPdf()->save(); + } + + // if ($this->request->has('cancel') && $this->request->input('cancel') == 'true') { + // $this->purchase_order = $this->purchase_order->service()->handleCancellation()->save(); + // } + + return $this->purchase_order; + } + + private function sendEmail() + { + + PurchaseOrderEmail::dispatch($this->purchase_order, $this->purchase_order->company); + + } +} diff --git a/app/Transformers/AccountTransformer.php b/app/Transformers/AccountTransformer.php index 661ad79b2ce9..502f0b9dedc5 100644 --- a/app/Transformers/AccountTransformer.php +++ b/app/Transformers/AccountTransformer.php @@ -86,6 +86,7 @@ class AccountTransformer extends EntityTransformer 'hosted_client_count' => (int) $account->hosted_client_count, 'hosted_company_count' => (int) $account->hosted_company_count, 'is_hosted' => (bool) Ninja::isHosted(), + // 'set_react_as_default_ap' => (bool) $account->set_react_as_default_ap ]; } diff --git a/app/Utils/Traits/MakesInvoiceValues.php b/app/Utils/Traits/MakesInvoiceValues.php index e59c59a61478..1b5c6985155a 100644 --- a/app/Utils/Traits/MakesInvoiceValues.php +++ b/app/Utils/Traits/MakesInvoiceValues.php @@ -265,6 +265,8 @@ trait MakesInvoiceValues */ public function transformLineItems($items, $table_type = '$product') :array { + $entity = $this->client ? $this->client : $this->company; + $data = []; if (! is_array($items)) { @@ -294,23 +296,23 @@ trait MakesInvoiceValues $data[$key][$table_type.'.item'] = is_null(optional($item)->item) ? $item->product_key : $item->item; $data[$key][$table_type.'.service'] = is_null(optional($item)->service) ? $item->product_key : $item->service; - $data[$key][$table_type.'.notes'] = Helpers::processReservedKeywords($item->notes, $this->client); - $data[$key][$table_type.'.description'] = Helpers::processReservedKeywords($item->notes, $this->client); + $data[$key][$table_type.'.notes'] = Helpers::processReservedKeywords($item->notes, $entity); + $data[$key][$table_type.'.description'] = Helpers::processReservedKeywords($item->notes, $entity); - $data[$key][$table_type . ".{$_table_type}1"] = $helpers->formatCustomFieldValue($this->client->company->custom_fields, "{$_table_type}1", $item->custom_value1, $this->client); - $data[$key][$table_type . ".{$_table_type}2"] = $helpers->formatCustomFieldValue($this->client->company->custom_fields, "{$_table_type}2", $item->custom_value2, $this->client); - $data[$key][$table_type . ".{$_table_type}3"] = $helpers->formatCustomFieldValue($this->client->company->custom_fields, "{$_table_type}3", $item->custom_value3, $this->client); - $data[$key][$table_type . ".{$_table_type}4"] = $helpers->formatCustomFieldValue($this->client->company->custom_fields, "{$_table_type}4", $item->custom_value4, $this->client); + $data[$key][$table_type . ".{$_table_type}1"] = $helpers->formatCustomFieldValue($this->company->custom_fields, "{$_table_type}1", $item->custom_value1, $entity); + $data[$key][$table_type . ".{$_table_type}2"] = $helpers->formatCustomFieldValue($this->company->custom_fields, "{$_table_type}2", $item->custom_value2, $entity); + $data[$key][$table_type . ".{$_table_type}3"] = $helpers->formatCustomFieldValue($this->company->custom_fields, "{$_table_type}3", $item->custom_value3, $entity); + $data[$key][$table_type . ".{$_table_type}4"] = $helpers->formatCustomFieldValue($this->company->custom_fields, "{$_table_type}4", $item->custom_value4, $entity); if($item->quantity > 0 || $item->cost > 0){ - $data[$key][$table_type.'.quantity'] = Number::formatValueNoTrailingZeroes($item->quantity, $this->client->currency()); + $data[$key][$table_type.'.quantity'] = Number::formatValueNoTrailingZeroes($item->quantity, $entity->currency()); - $data[$key][$table_type.'.unit_cost'] = Number::formatMoneyNoRounding($item->cost, $this->client); + $data[$key][$table_type.'.unit_cost'] = Number::formatMoneyNoRounding($item->cost, $entity); - $data[$key][$table_type.'.cost'] = Number::formatMoney($item->cost, $this->client); + $data[$key][$table_type.'.cost'] = Number::formatMoney($item->cost, $entity); - $data[$key][$table_type.'.line_total'] = Number::formatMoney($item->line_total, $this->client); + $data[$key][$table_type.'.line_total'] = Number::formatMoney($item->line_total, $entity); } else { @@ -326,13 +328,13 @@ trait MakesInvoiceValues } if(property_exists($item, 'gross_line_total')) - $data[$key][$table_type.'.gross_line_total'] = ($item->gross_line_total == 0) ? '' :Number::formatMoney($item->gross_line_total, $this->client); + $data[$key][$table_type.'.gross_line_total'] = ($item->gross_line_total == 0) ? '' :Number::formatMoney($item->gross_line_total, $entity); else $data[$key][$table_type.'.gross_line_total'] = ''; if (isset($item->discount) && $item->discount > 0) { if ($item->is_amount_discount) { - $data[$key][$table_type.'.discount'] = Number::formatMoney($item->discount, $this->client); + $data[$key][$table_type.'.discount'] = Number::formatMoney($item->discount, $entity); } else { $data[$key][$table_type.'.discount'] = floatval($item->discount).'%'; } @@ -376,13 +378,14 @@ trait MakesInvoiceValues private function makeLineTaxes() :string { $tax_map = $this->calc()->getTaxMap(); + $entity = $this->client ? $this->client : $this->company; $data = ''; foreach ($tax_map as $tax) { $data .= ''; $data .= ''.$tax['name'].''; - $data .= ''.Number::formatMoney($tax['total'], $this->client).''; + $data .= ''.Number::formatMoney($tax['total'], $entity).''; } return $data; @@ -395,6 +398,7 @@ trait MakesInvoiceValues private function makeTotalTaxes() :string { $data = ''; + $entity = $this->client ? $this->client : $this->company; if (! $this->calc()->getTotalTaxMap()) { return $data; @@ -403,7 +407,7 @@ trait MakesInvoiceValues foreach ($this->calc()->getTotalTaxMap() as $tax) { $data .= ''; $data .= ''.$tax['name'].''; - $data .= ''.Number::formatMoney($tax['total'], $this->client).''; + $data .= ''.Number::formatMoney($tax['total'], $entity).''; } return $data; @@ -427,13 +431,14 @@ trait MakesInvoiceValues private function totalTaxValues() :string { $data = ''; + $entity = $this->client ? $this->client : $this->company; if (! $this->calc()->getTotalTaxMap()) { return $data; } foreach ($this->calc()->getTotalTaxMap() as $tax) { - $data .= ''.Number::formatMoney($tax['total'], $this->client).''; + $data .= ''.Number::formatMoney($tax['total'], $entity).''; } return $data; @@ -455,11 +460,12 @@ trait MakesInvoiceValues private function lineTaxValues() :string { $tax_map = $this->calc()->getTaxMap(); + $entity = $this->client ? $this->client : $this->company; $data = ''; foreach ($tax_map as $tax) { - $data .= ''.Number::formatMoney($tax['total'], $this->client).''; + $data .= ''.Number::formatMoney($tax['total'], $entity).''; } return $data; @@ -481,7 +487,8 @@ trait MakesInvoiceValues */ public function generateCustomCSS() :string { - $settings = $this->client->getMergedSettings(); + + $settings = $this->client ? $this->client->getMergedSettings() : $this->company->settings; $header_and_footer = ' .header, .header-space { diff --git a/app/Utils/VendorHtmlEngine.php b/app/Utils/VendorHtmlEngine.php index 7e20a951684e..36cc99a9fb08 100644 --- a/app/Utils/VendorHtmlEngine.php +++ b/app/Utils/VendorHtmlEngine.php @@ -134,20 +134,15 @@ class VendorHtmlEngine $data['$entity.datetime'] = ['value' => $this->formatDatetime($this->entity->created_at, $this->company->date_format(), $this->company->locale()), 'label' => ctrans('texts.date')]; - $data['$payment_button'] = ['value' => ''.ctrans('texts.pay_now').'', 'label' => ctrans('texts.pay_now')]; - $data['$payment_link'] = ['value' => $this->invitation->getPaymentLink(), 'label' => ctrans('texts.pay_now')]; - - $data['$entity'] = ['value' => '', 'label' => ctrans('texts.purchase_order')]; $data['$number'] = ['value' => $this->entity->number ?: ' ', 'label' => ctrans('texts.purchase_order_number')]; $data['$number_short'] = ['value' => $this->entity->number ?: ' ', 'label' => ctrans('texts.purchase_order_number_short')]; $data['$entity.terms'] = ['value' => Helpers::processReservedKeywords(\nl2br($this->entity->terms), $this->company) ?: '', 'label' => ctrans('texts.invoice_terms')]; $data['$terms'] = &$data['$entity.terms']; - $data['$view_link'] = ['value' => ''.ctrans('texts.view_invoice').'', 'label' => ctrans('texts.view_invoice')]; + $data['$view_link'] = ['value' => ''.ctrans('texts.view_purchase_order').'', 'label' => ctrans('texts.view_purchase_order')]; $data['$viewLink'] = &$data['$view_link']; $data['$viewButton'] = &$data['$view_link']; $data['$view_button'] = &$data['$view_link']; - $data['$paymentButton'] = &$data['$payment_button']; $data['$view_url'] = ['value' => $this->invitation->getLink(), 'label' => ctrans('texts.view_invoice')]; $data['$date'] = ['value' => $this->translateDate($this->entity->date, $this->company->date_format(), $this->company->locale()) ?: ' ', 'label' => ctrans('texts.date')]; @@ -390,11 +385,6 @@ class VendorHtmlEngine $data['$autoBill'] = ['value' => ctrans('texts.auto_bill_notification_placeholder'), 'label' => '']; $data['$auto_bill'] = &$data['$autoBill']; - /*Payment Aliases*/ - $data['$paymentLink'] = &$data['$payment_link']; - $data['$payment_url'] = &$data['$payment_link']; - $data['$portalButton'] = &$data['$paymentLink']; - $data['$dir'] = ['value' => optional($this->company->language())->locale === 'ar' ? 'rtl' : 'ltr', 'label' => '']; $data['$dir_text_align'] = ['value' => optional($this->company->language())->locale === 'ar' ? 'right' : 'left', 'label' => '']; diff --git a/database/migrations/2022_06_10_030503_set_account_flag_for_react.php b/database/migrations/2022_06_10_030503_set_account_flag_for_react.php new file mode 100644 index 000000000000..a81f53fa4c3e --- /dev/null +++ b/database/migrations/2022_06_10_030503_set_account_flag_for_react.php @@ -0,0 +1,40 @@ +boolean('set_react_as_default_ap')->default(0); + // }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + // + } +} diff --git a/resources/lang/en/texts.php b/resources/lang/en/texts.php index 59a028251576..413a966fbe12 100644 --- a/resources/lang/en/texts.php +++ b/resources/lang/en/texts.php @@ -4619,8 +4619,10 @@ $LANG = array( 'activity_134' => ':user restored purchase order :purchase_order', 'activity_135' => ':user emailed purchase order :purchase_order', 'activity_136' => ':contact viewed purchase order :purchase_order', - 'purchase_order_subject' => '', - 'purchase_order_message' => '', + 'purchase_order_subject' => 'New Purchase Order :number from :account', + 'purchase_order_message' => 'To view your purchase order for :amount, click the link below.', + 'view_purchase_order' => 'View Purchase Order', + ); return $LANG;