Refactor bulk emails to use Email::class

This commit is contained in:
David Bomba 2024-11-10 20:07:25 +11:00
parent 1ddd4f64aa
commit adbb225633
10 changed files with 129 additions and 43 deletions

View File

@ -359,7 +359,7 @@ class BaseRule implements RuleInterface
public function tax($item = null): self public function tax($item = null): self
{ {
if ($this->client->is_tax_exempt || !property_exists($item, 'tax_id')) { if ($this->client->is_tax_exempt || !property_exists($item, 'tax_id') ) {
return $this->taxExempt($item); return $this->taxExempt($item);

View File

@ -72,6 +72,7 @@ class EmailController extends BaseController
$user = auth()->user(); $user = auth()->user();
$company = $entity_obj->company; $company = $entity_obj->company;
//@todo - need to resolve if this entity is email only
//Only handle Peppol Invoices for now. //double check if the identifier here was //Only handle Peppol Invoices for now. //double check if the identifier here was
if($entity_obj instanceof Invoice && !isset($entity_obj->sync->email)){ if($entity_obj instanceof Invoice && !isset($entity_obj->sync->email)){
// if($entity_obj instanceof Invoice && $company->isPeppolSender()){ // if($entity_obj instanceof Invoice && $company->isPeppolSender()){

View File

@ -144,7 +144,7 @@ class MailgunController extends BaseController
nlog($parts); nlog($parts);
if(count($parts) != 4 && $parts[0] != 'peppol' && stripos('db-ninja-0', $parts[3]) !== false) if(!in_array(count($parts), [4,5]) && $parts[0] != 'peppol' && stripos('db-ninja-0', $parts[3]) !== false)
return; return;
$entity = ucfirst($parts[1]); $entity = ucfirst($parts[1]);
@ -164,12 +164,10 @@ class MailgunController extends BaseController
return; return;
} }
foreach ($request->files as $file) { $this->saveDocuments($request->allFiles(), $entity, true);
$this->saveDocuments($file, $entity, true);
}
// if sync is empty OR there is a 5th part to the email - just save.
if(empty($entity->sync)) if(empty($entity->sync) || count($parts) == 5)
return; //just save the document, do not email it! return; //just save the document, do not email it!
$sync = $entity->sync; $sync = $entity->sync;

View File

@ -13,8 +13,10 @@ namespace App\Jobs\Invoice;
use App\Models\Invoice; use App\Models\Invoice;
use App\Models\Webhook; use App\Models\Webhook;
use App\Services\Email\Email;
use Illuminate\Bus\Queueable; use Illuminate\Bus\Queueable;
use App\Jobs\Entity\EmailEntity; use App\Jobs\Entity\EmailEntity;
use App\Services\Email\EmailObject;
use Illuminate\Queue\SerializesModels; use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Contracts\Queue\ShouldQueue;
@ -27,15 +29,24 @@ class BulkInvoiceJob implements ShouldQueue
use Queueable; use Queueable;
use SerializesModels; use SerializesModels;
public $invoice; private array $templates = [
'email_template_invoice',
'email_template_quote',
'email_template_credit',
'email_template_payment',
'email_template_payment_partial',
'email_template_statement',
'email_template_reminder1',
'email_template_reminder2',
'email_template_reminder3',
'email_template_reminder_endless',
'email_template_custom1',
'email_template_custom2',
'email_template_custom3',
'email_template_purchase_order',
];
public $reminder_template; public function __construct(public Invoice $invoice, public string $reminder_template){}
public function __construct(Invoice $invoice, string $reminder_template)
{
$this->invoice = $invoice;
$this->reminder_template = $reminder_template;
}
/** /**
* Execute the job. * Execute the job.
@ -49,7 +60,24 @@ class BulkInvoiceJob implements ShouldQueue
$this->invoice->service()->markSent()->save(); $this->invoice->service()->markSent()->save();
$this->invoice->invitations->load('contact.client.country', 'invoice.client.country', 'invoice.company')->each(function ($invitation) { $this->invoice->invitations->load('contact.client.country', 'invoice.client.country', 'invoice.company')->each(function ($invitation) {
EmailEntity::dispatch($invitation, $this->invoice->company, $this->reminder_template)->delay(now()->addSeconds(5)); // EmailEntity::dispatch($invitation, $this->invoice->company, $this->reminder_template)->delay(now()->addSeconds(5));
//@refactor 2024-11-10 - move email into EmailObject/Email::class
$template = $this->resolveTemplateString($this->reminder_template);
$mo = new EmailObject();
$mo->entity_id = $invitation->invoice_id;
$mo->template = $template; //full template name in use
$mo->email_template_body = $template;
$mo->email_template_subject = str_replace("template", "subject", $template);
$mo->entity_class = get_class($invitation->invoice);
$mo->invitation_id = $invitation->id;
$mo->client_id = $invitation->contact->client_id ?? null;
$mo->vendor_id = $invitation->contact->vendor_id ?? null;
Email::dispatch($mo, $invitation->company);
}); });
if ($this->invoice->invitations->count() >= 1) { if ($this->invoice->invitations->count() >= 1) {
@ -58,4 +86,20 @@ class BulkInvoiceJob implements ShouldQueue
} }
} }
private function resolveTemplateString(string $template): string
{
return match ($template) {
'reminder1' => 'email_template_reminder1',
'reminder2' => 'email_template_reminder2',
'reminder3' => 'email_template_reminder3',
'endless_reminder' => 'email_template_reminder_endless',
'custom1' => 'email_template_custom1',
'custom2' => 'email_template_custom2',
'custom3' => 'email_template_custom3',
default => "email_template_{$template}",
};
}
} }

View File

@ -191,7 +191,7 @@ class TemplateEmail extends Mailable
} }
} elseif ($this->invitation->quote) {//@phpstan-ignore-line } elseif ($this->invitation->quote) {//@phpstan-ignore-line
if ($this->invitation->quote->client->getSetting('enable_e_invoice') && $this->invitation->invoice->client->getSetting('ubl_email_attachment') && $this->company->account->hasFeature(Account::FEATURE_PDF_ATTACHMENT)) { if ($this->invitation->quote->client->getSetting('enable_e_invoice') && $this->invitation->quote->client->getSetting('ubl_email_attachment') && $this->company->account->hasFeature(Account::FEATURE_PDF_ATTACHMENT)) {
$xml_string = $this->invitation->quote->service()->getEQuote($this->invitation->contact); $xml_string = $this->invitation->quote->service()->getEQuote($this->invitation->contact);
if ($xml_string) { if ($xml_string) {
@ -200,7 +200,7 @@ class TemplateEmail extends Mailable
} }
} elseif ($this->invitation->purchase_order) { } elseif ($this->invitation->purchase_order) {
if ($this->invitation->purchase_order->vendor->getSetting('enable_e_invoice') && $this->invitation->invoice->client->getSetting('ubl_email_attachment') && $this->company->account->hasFeature(Account::FEATURE_PDF_ATTACHMENT)) { if ($this->invitation->purchase_order->vendor->getSetting('enable_e_invoice') && $this->invitation->purchase_order->vendor->getSetting('ubl_email_attachment') && $this->company->account->hasFeature(Account::FEATURE_PDF_ATTACHMENT)) {
$xml_string = $this->invitation->purchase_order->service()->getEPurchaseOrder($this->invitation->contact); $xml_string = $this->invitation->purchase_order->service()->getEPurchaseOrder($this->invitation->contact);
if ($xml_string) { if ($xml_string) {

View File

@ -581,9 +581,13 @@ class Mutator implements MutatorInterface
{ {
$code = $this->getClientRoutingCode(); $code = $this->getClientRoutingCode();
if($this->invoice->client->classification == 'individual' || (strlen($this->invoice->client->vat_number ?? '') < 2 && strlen($this->invoice->client->id_number ?? '') < 2)){ if($this->invoice->client->classification == 'government'){
$this->setEmailRouting("peppol_invoice_{$this->invoice->id}_{$this->invoice->company->db}_storeonly@mail.invoicing.co");
}
else if($this->invoice->client->classification == 'individual' || (strlen($this->invoice->client->vat_number ?? '') < 2 && strlen($this->invoice->client->id_number ?? '') < 2)){
return $this->setEmailRouting($this->getIndividualEmailRoute()); return $this->setEmailRouting($this->getIndividualEmailRoute());
}else { }
else {
$this->setEmailRouting("peppol_invoice_{$this->invoice->id}_{$this->invoice->company->db}_storeonly@mail.invoicing.co"); $this->setEmailRouting("peppol_invoice_{$this->invoice->id}_{$this->invoice->company->db}_storeonly@mail.invoicing.co");
} }
@ -592,6 +596,9 @@ class Mutator implements MutatorInterface
else else
$vat = $this->invoice->client->vat_number; $vat = $this->invoice->client->vat_number;
if($this->invoice->client->country->iso_3166_2 == 'DE' && $this->invoice->client->classification == 'government')
$vat = $this->invoice->client->routing_id;
$this->setStorecoveMeta($this->buildRouting([ $this->setStorecoveMeta($this->buildRouting([
["scheme" => $code, "id" => $vat] ["scheme" => $code, "id" => $vat]
])); ]));
@ -665,7 +672,7 @@ class Mutator implements MutatorInterface
private function setStorecoveMeta(array $meta): self private function setStorecoveMeta(array $meta): self
{ {
$this->storecove_meta = array_merge($this->storecove_meta, $meta); $this->storecove_meta = array_merge_recursive($this->storecove_meta, $meta);
return $this; return $this;
} }

View File

@ -365,8 +365,6 @@ class StorecoveAdapter
$this->nexus = $company_country_code; $this->nexus = $company_country_code;
} elseif (in_array($client_country_code, $eu_countries)) { } elseif (in_array($client_country_code, $eu_countries)) {
//EU Sale where Company country != Client Country
// First, determine if we're over threshold // First, determine if we're over threshold
$is_over_threshold = isset($this->ninja_invoice->company->tax_data->regions->EU->has_sales_above_threshold) && $is_over_threshold = isset($this->ninja_invoice->company->tax_data->regions->EU->has_sales_above_threshold) &&
$this->ninja_invoice->company->tax_data->regions->EU->has_sales_above_threshold; $this->ninja_invoice->company->tax_data->regions->EU->has_sales_above_threshold;
@ -405,6 +403,19 @@ class StorecoveAdapter
} }
if($company_country_code == 'DE' && $client_country_code == 'DE' && $this->ninja_invoice->client->classification == 'government') {
$this->removeSupplierVatNumber();
}
return $this;
}
private function removeSupplierVatNumber(): self
{
$asp = $this->storecove_invoice->getAccountingSupplierParty();
$asp->setPublicIdentifiers([]);
$this->storecove_invoice->setAccountingSupplierParty($asp);
return $this; return $this;
} }

View File

@ -407,7 +407,6 @@ class Peppol extends AbstractService
$id->value = $this->invoice->po_number; $id->value = $this->invoice->po_number;
$order_reference->ID = $id; $order_reference->ID = $id;
$this->p_invoice->OrderReference = $order_reference; $this->p_invoice->OrderReference = $order_reference;
} }
@ -1069,7 +1068,6 @@ class Peppol extends AbstractService
$party->PartyTaxScheme[] = $pts; $party->PartyTaxScheme[] = $pts;
} }
$party_name = new PartyName(); $party_name = new PartyName();

View File

@ -13,23 +13,16 @@ namespace App\Services\Quote;
use App\Models\Webhook; use App\Models\Webhook;
use App\Models\ClientContact; use App\Models\ClientContact;
use App\Services\Email\Email;
use App\Jobs\Entity\EmailEntity; use App\Jobs\Entity\EmailEntity;
use App\Models\Quote;
use App\Services\Email\EmailObject;
class SendEmail class SendEmail
{ {
public $quote;
protected $reminder_template; public function __construct(public Quote $quote, public ?string $reminder_template = null, protected ?ClientContact $contact = null)
protected $contact;
public function __construct($quote, $reminder_template = null, ClientContact $contact = null)
{ {
$this->quote = $quote;
$this->reminder_template = $reminder_template;
$this->contact = $contact;
} }
/** /**
@ -39,15 +32,31 @@ class SendEmail
public function run() public function run()
{ {
if (! $this->reminder_template) { $this->reminder_template = $this->reminder_template ? "email_template_{$this->reminder_template}" : "email_template_".$this->quote->calculateTemplate('quote');
$this->reminder_template = $this->quote->calculateTemplate('quote'); // if (! $this->reminder_template) {
} // $this->reminder_template = $this->quote->calculateTemplate('quote');
// }
$this->quote->service()->markSent()->save(); $this->quote->service()->markSent()->save();
$this->quote->invitations->each(function ($invitation) { $this->quote->invitations->each(function ($invitation) {
if (! $invitation->contact->trashed() && $invitation->contact->email) { if (! $invitation->contact->trashed() && $invitation->contact->email) {
EmailEntity::dispatch($invitation, $invitation->company, $this->reminder_template); // EmailEntity::dispatch($invitation, $invitation->company, $this->reminder_template);
//@refactor 2024-11-10
$mo = new EmailObject();
$mo->entity_id = $invitation->quote_id;
$mo->template = $this->reminder_template; //full template name in use
$mo->email_template_body = $this->reminder_template;
$mo->email_template_subject = str_replace("template", "subject", $this->reminder_template);
$mo->entity_class = get_class($invitation->quote);
$mo->invitation_id = $invitation->id;
$mo->client_id = $invitation->contact->client_id ?? null;
$mo->vendor_id = $invitation->contact->vendor_id ?? null;
Email::dispatch($mo, $invitation->company);
} }
}); });

View File

@ -15,8 +15,10 @@ use App\Utils\Ninja;
use App\Models\Quote; use App\Models\Quote;
use App\Models\Webhook; use App\Models\Webhook;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use App\Services\Email\Email;
use App\Jobs\Entity\EmailEntity; use App\Jobs\Entity\EmailEntity;
use App\Services\AbstractService; use App\Services\AbstractService;
use App\Services\Email\EmailObject;
use App\Events\Quote\QuoteWasEmailed; use App\Events\Quote\QuoteWasEmailed;
use App\Utils\Traits\GeneratesCounter; use App\Utils\Traits\GeneratesCounter;
@ -80,9 +82,25 @@ class TriggeredActions extends AbstractService
{ {
$reminder_template = $this->quote->calculateTemplate('quote'); $reminder_template = $this->quote->calculateTemplate('quote');
// $reminder_template = 'email_template_quote'; // $reminder_template = 'email_template_quote';
// $quote_template = 'email_template_reminder1
$reminder_template = "email_template_{$reminder_template}";
$this->quote->invitations->load('contact.client.country', 'quote.client.country', 'quote.company')->each(function ($invitation) use ($reminder_template) { $this->quote->invitations->load('contact.client.country', 'quote.client.country', 'quote.company')->each(function ($invitation) use ($reminder_template) {
EmailEntity::dispatch($invitation, $this->quote->company, $reminder_template); // EmailEntity::dispatch($invitation, $this->quote->company, $reminder_template);
$mo = new EmailObject();
$mo->entity_id = $invitation->quote_id;
$mo->template = $reminder_template; //full template name in use
$mo->email_template_body = $reminder_template;
$mo->email_template_subject = str_replace("template", "subject", $reminder_template);
$mo->entity_class = get_class($invitation->quote);
$mo->invitation_id = $invitation->id;
$mo->client_id = $invitation->contact->client_id ?? null;
$mo->vendor_id = $invitation->contact->vendor_id ?? null;
Email::dispatch($mo, $invitation->company);
}); });
if ($this->quote->invitations->count() > 0) { if ($this->quote->invitations->count() > 0) {