diff --git a/app/controllers/documents_controller.php b/app/controllers/documents_controller.php index b9c58126..798b3f0f 100755 --- a/app/controllers/documents_controller.php +++ b/app/controllers/documents_controller.php @@ -389,7 +389,6 @@ ENDINSTRUCTIONS; - if(isset($source_document_id)) { //This is not ideal. But nothing else is either. $sourceDoc = $this->Document->find('first', array('conditions' => array('Document.id' => $source_document_id))); @@ -1114,21 +1113,18 @@ EOT; $this->Email->delivery = 'smtp'; $document = $this->Document->read(null,$id); - if(empty($document['Document']['pdf_filename'])) { $this->Session->setFlash(__('Error. Please generate the PDF before attempting to email it', true)); return; } else { $pdf_dir = Configure::read('pdf_directory'); - $attachment_files = array($pdf_dir.$document['Document']['pdf_filename']); foreach($document['DocumentAttachment'] as $document_attachment) { - $attachment = $this->Document->DocumentAttachment->Attachment->read(null, $document_attachment['attachment_id']); - $attachment_files[] = $attachment['Attachment']['file']; + $attachment = $this->Document->DocumentAttachment->Attachment->read(null, $document_attachment['attachment_id']); + $attachment_files[] = $attachment['Attachment']['file']; } $this->Email->attachments = $attachment_files; - } $enquiry = $this->Document->getEnquiry($document); @@ -1209,6 +1205,221 @@ EOT; } + function format_email($email) { + $email = trim($email); + // Basic RFC 5322 email validation + if (!preg_match('/^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$/', $email)) { + return ''; + } + return "$email <$email>"; +} + + function parse_email_to_array($input) { + try { + if (empty($input) || !is_string($input)) { + return array(); + } + $input = trim($input); + if ($input === '') { + return array(); + } + if (strpos($input, ',') !== false) { + $parts = explode(',', $input); + $result = array(); + foreach ($parts as $email) { + $email = $this->format_email($email); + if ($email !== '') { + $result[] = $email; + } + } + return $result; + } else { + $result = $this->format_email($input); + $array[] = $result; + return $array; + } + } catch (Exception $e) { + return array(); + } +} + + /** + * Email the PDF(document + attachments) for this Document to custom recipients. + * + * @param int $id - Document ID + * @param string $to - Recipient email address (comma-separated if multiple) + * @param string|null $cc - CC email address(es), optional (comma-separated) + * @param string|null $bcc - BCC email address(es), optional (comma-separated) + */ +function email_pdf_with_custom_recipients($id = null, $to = null, $cc = null, $bcc = null) { + // Disable automatic rendering of a view + $this->autoRender = false; + + // Retrieve recipient emails from form data if not provided as arguments + if (empty($to) && !empty($this->params['form']['to'])) { + $to = $this->params['form']['to']; + } + if (empty($cc) && isset($this->params['form']['cc'])) { + $cc = $this->params['form']['cc']; + } + if (empty($bcc) && isset($this->params['form']['bcc'])) { + $bcc = $this->params['form']['bcc']; + } + + // Basic validation for required parameters + if (empty($id) || empty($to)) { + $msg = 'Document ID and recipient email are required.'; + echo json_encode(array('success' => false, 'message' => $msg)); + return; + } + + // Configure SMTP settings for email delivery + $this->Email->smtpOptions = Configure::read('smtp_settings'); + $this->Email->delivery = 'smtp'; + + // Load the document and its attachments + $document = $this->Document->read(null, $id); + error_log("[email_pdf_with_custom_recipients] Document loaded: " . print_r($document['Document'], true)); + error_log("[email_pdf_with_custom_recipients] DocumentAttachments: " . print_r($document['DocumentAttachment'], true)); + if (empty($document) || empty($document['Document'])) { + $msg = 'Document not found.'; + echo json_encode(array('success' => false, 'message' => $msg)); + return; + } + + // Ensure the PDF has been generated before emailing + if (empty($document['Document']['pdf_filename'])) { + $msg = 'Error. Please generate the PDF before attempting to email it'; + echo json_encode(array('success' => false, 'message' => $msg)); + return; + } + + // Build the list of attachments (PDF + any additional attachments) + $pdf_dir = Configure::read('pdf_directory'); + $attachment_files = array($pdf_dir.$document['Document']['pdf_filename']); + foreach($document['DocumentAttachment'] as $document_attachment) { + $attachment = $this->Document->DocumentAttachment->Attachment->read(null, $document_attachment['attachment_id']); + $attachment_files[] = $attachment['Attachment']['file']; + error_log("[email_pdf_with_custom_recipients] Added attachment: " . $attachment['Attachment']['file']); + } + if (!empty($document['DocumentAttachment'])) { + foreach ($document['DocumentAttachment'] as $document_attachment) { + if (!empty($document_attachment['attachment_id'])) { + $attachment = $this->Document->DocumentAttachment->Attachment->read(null, $document_attachment['attachment_id']); + if (!empty($attachment['Attachment']['file'])) { + $attachment_files[] = $attachment['Attachment']['file']; + error_log("[email_pdf_with_custom_recipients] Added attachment: " . $attachment['Attachment']['file']); + } + } + } + } + error_log("[email_pdf_with_custom_recipients] All attachments: " . print_r($attachment_files, true)); + $this->Email->attachments = $attachment_files; + + // Get related enquiry for the document + $enquiry = $this->Document->getEnquiry($document); + + // Parse and validate recipient email addresses + $toArray = $this->parse_email_to_array($to); + if (empty($toArray)) { + $msg = 'Invalid recipient email address.'; + echo json_encode(array('success' => false, 'message' => $msg)); + return; + } else { + $this->Email->to = implode(', ', $toArray); + } + $ccArray = $this->parse_email_to_array($cc); + if (!empty($ccArray)) { + $this->Email->cc = $ccArray; + } + $bccArray = $this->parse_email_to_array($bcc); + if (!empty($bccArray)) { + $this->Email->bcc = $bccArray; + } + + // Set reply-to and from addresses + $this->Email->replyTo = 'CMC Technologies - Sales '; + $this->Email->from = 'CMC Technologies - Sales '; + + // Determine document type, email template, and subject + $docType = $this->Document->getDocType($document); + $template = $docType . '_email'; + $subject = !empty($enquiry['Enquiry']['title']) ? $enquiry['Enquiry']['title'] . ' ' : 'Document'; + error_log("[email_pdf_with_custom_recipients] Enquiry Title: " . empty($enquiry['Enquiry']['title']) . $enquiry['Enquiry']['title']); + + // Customise subject and template based on document type + switch($docType) { + case 'quote': + $subject = !empty($enquiry['Enquiry']['title']) ? "Quotation: " . $enquiry['Enquiry']['title'] : 'Quotation'; + break; + case 'invoice': + $subject = $this->invoice_email_subject($document); + if (!empty($document['Invoice']['id'])) { + $this->set('invoice', $this->Document->Invoice->find('first', array('conditions'=>array('Invoice.id'=>$document['Invoice']['id'])))); + } + if (!empty($document['Invoice']['job_id'])) { + $this->set('job', $this->Document->Invoice->Job->find('first', array('conditions'=>array('Job.id'=>$document['Invoice']['job_id'])))); + } + break; + case 'purchaseOrder': + $subject .= "Purchase Order"; + $primary_contact = null; + if (!empty($document['PurchaseOrder']['principle_id'])) { + $primary_contact = $this->Document->User->find('first', array('conditions'=>array('User.principle_id' => $document['PurchaseOrder']['principle_id'],'User.primary_contact' => 1))); + } + if(empty($primary_contact)) { + $msg = 'Unable to send. No primary Principle Contact'; + echo json_encode(array('success' => false, 'message' => $msg)); + return; + } + $subject = $this->po_email_subject($document['PurchaseOrder']); + if (!empty($document['OrderAcknowledgement']['job_id'])) { + $this->set('job', $this->Document->PurchaseOrder->Job->find('first', array('conditions'=>array('Job.id'=>$document['OrderAcknowledgement']['job_id'])))); + } + break; + case 'orderAck': + $subject = $this->orderack_email_subject($document); + if (!empty($document['OrderAcknowledgement']['job_id'])) { + $this->set('job', $this->Document->OrderAcknowledgement->Job->find('first', array('conditions'=>array('Job.id'=>$document['OrderAcknowledgement']['job_id'])))); + } + if (!empty($document['OrderAcknowledgement']['signature_required'])) { + $template = 'orderAck_email_signature_required'; + } + break; + case 'packingList': + $subject = $this->packing_list_email_subject($document); + break; + } + + // Set email template and other parameters + $this->Email->template = $template; + $this->Email->subject = $subject; + $this->Email->sendAs = 'both'; + $this->Email->charset = 'iso-8859-1'; + $this->set('enquiry', $enquiry); + $this->set('document', $document); + $this->set('DocFullName', $this->Document->getDocFullName($document['Document']['type'])); + + // Attempt to send the email and handle errors + $sent = false; + try { + $sent = $this->Email->send(); + } catch (Exception $e) { + $msg = 'Exception: ' . $e->getMessage(); + echo json_encode(array('success' => false, 'message' => $msg)); + return; + } + if ($sent) { + echo json_encode(array('success' => true, 'message' => 'The Email has been sent')); + return; + } else { + $msg = 'The Email has NOT been sent'; + echo json_encode(array('success' => false, 'message' => $msg, 'smtp_errors' => $this->Email->smtpError)); + return; + } + echo json_encode(array('success' => false, 'message' => 'No response from email function')); +} + // generateShippingReference builds the Shipping Instructions: with the PO number and job titles. function generateShippingInstructions($document_id) { $this->layout = 'ajax'; @@ -1331,5 +1542,4 @@ ENDINSTRUCTIONS; } return $newDoc[$model]; } - } diff --git a/app/views/elements/document_invoice_view.ctp b/app/views/elements/document_invoice_view.ctp index 20970ace..c2070307 100755 --- a/app/views/elements/document_invoice_view.ctp +++ b/app/views/elements/document_invoice_view.ctp @@ -6,9 +6,147 @@
- +
+ + + + + +

Create new Documents based on this

    @@ -64,3 +202,86 @@ + +