mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-05-24 02:14:21 -04:00
Purchase Order Emails
This commit is contained in:
parent
646091f89e
commit
90bff41600
@ -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()
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
102
app/Jobs/PurchaseOrder/PurchaseOrderEmail.php
Normal file
102
app/Jobs/PurchaseOrder/PurchaseOrderEmail.php
Normal file
@ -0,0 +1,102 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2022. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\Jobs\PurchaseOrder;
|
||||
|
||||
use App\Events\PurchaseOrder\PurchaseOrderWasEmailed;
|
||||
use App\Jobs\Mail\NinjaMailerJob;
|
||||
use App\Jobs\Mail\NinjaMailerObject;
|
||||
use App\Libraries\MultiDB;
|
||||
use App\Mail\Engine\PurchaseOrderEmailEngine;
|
||||
use App\Mail\VendorTemplateEmail;
|
||||
use App\Models\Company;
|
||||
use App\Models\PurchaseOrder;
|
||||
use App\Utils\Ninja;
|
||||
use Exception;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Support\Facades\App;
|
||||
|
||||
class PurchaseOrderEmail implements ShouldQueue
|
||||
{
|
||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||
|
||||
public PurchaseOrder $purchase_order;
|
||||
|
||||
public Company $company;
|
||||
|
||||
public $template_data;
|
||||
|
||||
public $tries = 1;
|
||||
|
||||
public function __construct(PurchaseOrder $purchase_order, Company $company, $template_data = null)
|
||||
{
|
||||
$this->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)));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
207
app/Mail/Engine/PurchaseOrderEmailEngine.php
Normal file
207
app/Mail/Engine/PurchaseOrderEmailEngine.php
Normal file
@ -0,0 +1,207 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2022. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\Mail\Engine;
|
||||
|
||||
use App\DataMapper\EmailTemplateDefaults;
|
||||
use App\Jobs\Entity\CreateEntityPdf;
|
||||
use App\Models\Account;
|
||||
use App\Models\Expense;
|
||||
use App\Models\PurchaseOrder;
|
||||
use App\Models\Task;
|
||||
use App\Models\Vendor;
|
||||
use App\Models\VendorContact;
|
||||
use App\Utils\HtmlEngine;
|
||||
use App\Utils\Ninja;
|
||||
use App\Utils\Number;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use App\Utils\VendorHtmlEngine;
|
||||
use Illuminate\Support\Facades\App;
|
||||
use Illuminate\Support\Facades\Lang;
|
||||
|
||||
class PurchaseOrderEmailEngine extends BaseEmailEngine
|
||||
{
|
||||
use MakesHash;
|
||||
|
||||
public $invitation;
|
||||
|
||||
public Vendor $vendor;
|
||||
|
||||
public PurchaseOrder $purchase_order;
|
||||
|
||||
public $contact;
|
||||
|
||||
public $reminder_template;
|
||||
|
||||
public $template_data;
|
||||
|
||||
public function __construct($invitation, $reminder_template, $template_data)
|
||||
{
|
||||
$this->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 .= '<div class="center">$view_button</div>';
|
||||
|
||||
}
|
||||
$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("<a href='{$this->invitation->getLink()}'>".ctrans('texts.view_purchase_order').'</a>')
|
||||
->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;
|
||||
}
|
||||
}
|
132
app/Mail/VendorTemplateEmail.php
Normal file
132
app/Mail/VendorTemplateEmail.php
Normal file
@ -0,0 +1,132 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2022. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\Mail;
|
||||
|
||||
use App\Jobs\Invoice\CreateUbl;
|
||||
use App\Models\Account;
|
||||
use App\Models\Client;
|
||||
use App\Models\User;
|
||||
use App\Models\VendorContact;
|
||||
use App\Services\PdfMaker\Designs\Utilities\DesignHelpers;
|
||||
use App\Utils\HtmlEngine;
|
||||
use App\Utils\Ninja;
|
||||
use App\Utils\TemplateEngine;
|
||||
use App\Utils\VendorHtmlEngine;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Mail\Mailable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class VendorTemplateEmail extends Mailable
|
||||
{
|
||||
|
||||
private $build_email;
|
||||
|
||||
private $vendor;
|
||||
|
||||
private $contact;
|
||||
|
||||
private $company;
|
||||
|
||||
private $invitation;
|
||||
|
||||
public function __construct($build_email, VendorContact $contact, $invitation = null)
|
||||
{
|
||||
$this->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;
|
||||
}
|
||||
}
|
@ -57,6 +57,7 @@ class Account extends BaseModel
|
||||
'utm_content',
|
||||
'user_agent',
|
||||
'platform',
|
||||
// 'set_react_as_default_ap',
|
||||
];
|
||||
|
||||
/**
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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']],
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
65
app/Services/PurchaseOrder/TriggeredActions.php
Normal file
65
app/Services/PurchaseOrder/TriggeredActions.php
Normal file
@ -0,0 +1,65 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2022. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\Services\PurchaseOrder;
|
||||
|
||||
use App\Events\Invoice\InvoiceWasEmailed;
|
||||
use App\Events\PurchaseOrder\PurchaseOrderWasEmailed;
|
||||
use App\Jobs\Entity\EmailEntity;
|
||||
use App\Jobs\PurchaseOrder\PurchaseOrderEmail;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\PurchaseOrder;
|
||||
use App\Services\AbstractService;
|
||||
use App\Utils\Ninja;
|
||||
use App\Utils\Traits\GeneratesCounter;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class TriggeredActions extends AbstractService
|
||||
{
|
||||
use GeneratesCounter;
|
||||
|
||||
private $request;
|
||||
|
||||
private $purchase_order;
|
||||
|
||||
public function __construct(PurchaseOrder $purchase_order, Request $request)
|
||||
{
|
||||
$this->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);
|
||||
|
||||
}
|
||||
}
|
@ -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
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -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 .= '<tr class="line_taxes">';
|
||||
$data .= '<td>'.$tax['name'].'</td>';
|
||||
$data .= '<td>'.Number::formatMoney($tax['total'], $this->client).'</td></tr>';
|
||||
$data .= '<td>'.Number::formatMoney($tax['total'], $entity).'</td></tr>';
|
||||
}
|
||||
|
||||
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 .= '<tr class="total_taxes">';
|
||||
$data .= '<td>'.$tax['name'].'</td>';
|
||||
$data .= '<td>'.Number::formatMoney($tax['total'], $this->client).'</td></tr>';
|
||||
$data .= '<td>'.Number::formatMoney($tax['total'], $entity).'</td></tr>';
|
||||
}
|
||||
|
||||
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 .= '<span>'.Number::formatMoney($tax['total'], $this->client).'</span>';
|
||||
$data .= '<span>'.Number::formatMoney($tax['total'], $entity).'</span>';
|
||||
}
|
||||
|
||||
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 .= '<span>'.Number::formatMoney($tax['total'], $this->client).'</span>';
|
||||
$data .= '<span>'.Number::formatMoney($tax['total'], $entity).'</span>';
|
||||
}
|
||||
|
||||
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 {
|
||||
|
@ -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' => '<a class="button" href="'.$this->invitation->getPaymentLink().'">'.ctrans('texts.pay_now').'</a>', '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' => '<a class="button" href="'.$this->invitation->getLink().'">'.ctrans('texts.view_invoice').'</a>', 'label' => ctrans('texts.view_invoice')];
|
||||
$data['$view_link'] = ['value' => '<a class="button" href="'.$this->invitation->getLink().'">'.ctrans('texts.view_purchase_order').'</a>', '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' => ''];
|
||||
|
||||
|
@ -0,0 +1,40 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2022. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class SetAccountFlagForReact extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Illuminate\Support\Facades\Artisan::call('ninja:design-update');
|
||||
|
||||
// Schema::table('accounts', function (Blueprint $table) {
|
||||
// $table->boolean('set_react_as_default_ap')->default(0);
|
||||
// });
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user